<!DOCTYPE html>
<html>

 <head>

  <meta charset="utf-8"/>
<title>Exported Data</title>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>

  <link href="css/style.css" rel="stylesheet"/>

  <script src="js/script.js" type="text/javascript">

  </script>

 </head>

 <body onload="CheckLocation();">

  <div class="page_wrap">

   <div class="page_header">

    <div class="content">

     <div class="text bold">
Bash Days | Linux | DevOps 
     </div>

    </div>

   </div>

   <div class="page_body chat_page">

    <div class="history">

     <div class="message service" id="message-1">

      <div class="body details">
2 June 2023
      </div>

     </div>

     <div class="message service" id="message1">

      <div class="body details">
Channel &laquo;BASH&raquo; created
      </div>

     </div>

     <div class="message service" id="message-2">

      <div class="body details">
7 June 2023
      </div>

     </div>

     <div class="message default clearfix" id="message15">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.06.2023 17:19:47 +07">
17:19
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<a href = "stickers/sticker.webp">😀</a><a href = "stickers/sticker (1).webp">😃</a><a href = "stickers/sticker (2).webp">😄</a><a href = "stickers/sticker (3).webp">😁</a><a href = "stickers/sticker (4).webp">😆</a><br><br><a href = "stickers/sticker (5).webp">🔧</a> Утилиты: <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><br><a href = "stickers/sticker (6).webp">💳</a> Таблицы: <a href="" onclick="return ShowHashtag(&quot;sheets&quot;)">#sheets</a><br><a href = "stickers/sticker (7).webp">⚙</a> Скрипты: <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><br><a href = "stickers/sticker (8).webp">🎙</a> Мониторинг: <a href="" onclick="return ShowHashtag(&quot;monitoring&quot;)">#monitoring</a><br><a href = "stickers/sticker (9).webp">🤔</a> Отладка: <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><br><a href = "stickers/sticker (10).webp">🎃</a> Линукс: <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><br><a href = "stickers/sticker (11).webp">✉️</a> Nginx: <a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><br><a href = "stickers/sticker (12).webp">📦</a> GIT: <a href="" onclick="return ShowHashtag(&quot;git&quot;)">#git</a><br><a href = "stickers/sticker (13).webp">📊</a> Mysql: <a href="" onclick="return ShowHashtag(&quot;mysql&quot;)">#mysql</a><br><a href = "stickers/sticker (14).webp">📱</a> Сервисы: <a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><br><a href = "stickers/sticker (15).webp">👻</a> Игры: <a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><br><a href = "stickers/sticker (16).webp">🌐</a> Сети: <a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><br><a href = "stickers/sticker (17).webp">💬</a> Будни: <a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-3">

      <div class="body details">
18 June 2023
      </div>

     </div>

     <div class="message default clearfix" id="message18">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.06.2023 18:44:39 +07">
18:44
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Animation
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
36.8 KB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Подвернулась интересная утилита Spacer работающая в каскаде с <code>tail -f</code>, которая разделяет «линией» активность в логах.<br><br>До этого я (да и многие из вас) обычно несколько раз нажимал Enter. Теперь достаточно соорудить нечто такое и радоваться:<br><br><pre>tail -f /var/log/nginx/error.log | spacer<br><br></pre>Конечно это не замена агрегаторам ELK и LOKI, но обязательно пригодится разработчикам и девопсам как быстрое решение. Думаю с docker logs так же будет работать.<br><br><a href = "stickers/AnimatedSticker.tgs">🐱</a> <strong>Spacer на </strong><a href="https://github.com/samwho/spacer">гитхабе<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>— <br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message19">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.06.2023 19:56:26 +07">
19:56
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_1@18-06-2023_19-56-26.jpg">

         <img class="photo" src="photos/photo_1@18-06-2023_19-56-26_thumb.jpg" style="width: 260px; height: 195px"/>

        </a>

       </div>

       <div class="text">
Табличка консольных инструментов для наблюдения и дебага на linux машинах. Хотя справедливо можно сказать, что и для других операционных систем данные утилиты актуальны.<br><br>Я в повседневной работе использую, ну процентов 30 наверное из того, что есть на картинке. Но про каждую расскажу вам отдельным постом. В общем мастхев, забирай на вооружение если чего-то не знал.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;sheets&quot;)">#sheets</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-4">

      <div class="body details">
29 June 2023
      </div>

     </div>

     <div class="message default clearfix" id="message20">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="29.06.2023 21:18:01 +07">
21:18
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_2@29-06-2023_21-18-01.jpg">

         <img class="photo" src="photos/photo_2@29-06-2023_21-18-01_thumb.jpg" style="width: 260px; height: 218px"/>

        </a>

       </div>

       <div class="text">
<strong>Утилита ncdu: эффективный инструмент для борьбы с переполнением дискового пространства<br><br></strong>Перво-наперво что мы делаем при инцидентах с серверами, это проверяем свободное место на диске. Зачастую проблема именно в этом, к примеру диск переполнился жирным лог файлом или наплодилось куча мусора в <a href="" onclick="return ShowBotCommand(&quot;tmp&quot;)">/tmp</a> папке, а может быть система резервного копирования вышла из-под контроля.<br><br>Для того чтобы не заморачиваться с командами <code>du</code> и <code>find</code>, есть прекрасная утилита, которая называется <strong>ncdu</strong>.<br><br>ncdu имеет мощный функционал, у неё много ключей для запуска, но в повседневной работе, мы используем ее с дефолтными параметрами:<br><br><pre># cd /<br># ncdu<br><br></pre>После запуска строится удобное дерево в процентном соотношении занятого дискового пространства, удобная навигация, ну а <strong>самое главное</strong> есть возможность прямо из нее удалять жирные файлы (нажать на файле или каталоге букву <strong>d</strong>). <br><br><em>Утилита мастхев, которая ежедневно экономит нам кучу времени и нервов. Рекомендуем.<br><br></em><strong>установка элементарная<br><br></strong>ubuntu:<code> apt install ncdu<br></code>osx:<code> brew install ncdu<br></code>centos:<code> yum install ncdu<br><br></code><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-5">

      <div class="body details">
30 June 2023
      </div>

     </div>

     <div class="message default clearfix" id="message22">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.06.2023 14:03:10 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_3@30-06-2023_14-03-10.jpg">

         <img class="photo" src="photos/photo_3@30-06-2023_14-03-10_thumb.jpg" style="width: 260px; height: 217px"/>

        </a>

       </div>

       <div class="text">
<strong>mytop</strong> — это отличная обертка для мониторинга mysql, я применяю её довольно часто, чтобы в реальном времени отследить какие запросы нагружают базу и откуда растут ноги.<br><br>Конечно можно законектится в сам mysql и выполнить SHOW FULL PROCESSLIST, но <strong>mytop</strong> делает это автоматически, регулярно запрашивая PROCESSLIST и STATUS.<br><br>По умолчанию информация о длинных запросах для удобства обрезается. Чтобы посмотреть полный запрос к базе, необходимо нажать букву <strong>f</strong> и ввести ID потока (треда).<br><br>Утилиту нужно сконфигурировать через конфиг файл <code>/root/.mytop</code>. Минимальный конфиг .mytop выглядит так:<br><br><pre>user=db_user<br>pass=superpassword<br>delay=5<br>db=db_base<br><br></pre>Через конфиг <code>.mytop</code> так же возможно сконфигурировать работу утилиты с удалёнными серверами, достаточно указать ip адрес сервера и порт на котором у вас крутится mysql. Но я обычно ставлю ее на тот же сервер где у нас крутится база.<br><br>Устанавливается обычным <code>apt install mytop</code>, а для других дистрибутивов и операционных систем с помощью brew/yum/pacman<br><br><em>mytop достаточно хороший инструмент для отладки, берите на вооружение<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-6">

      <div class="body details">
1 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message23">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.07.2023 15:02:26 +07">
15:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_4@01-07-2023_15-02-26.jpg">

         <img class="photo" src="photos/photo_4@01-07-2023_15-02-26_thumb.jpg" style="width: 260px; height: 225px"/>

        </a>

       </div>

       <div class="text">
<strong>pstree</strong> — незаменимый инструмент в работе, утилита визуально выводит компактное дерево всех запущенных процессов. Можно сказать что это аналог команды <strong>ps</strong>, но на стероидах и самое главное для людей.<br><br>Утилита имеет множество ключей для запуска, но я использую ее в стандартном режиме. Этого вполне достаточно, чтобы за несколько секунд понять что у меня запущено, а что нет.<br><br><strong>pstree</strong> стакает идентичные ветви, помещая их в квадратные скобки и добавляет к ним целое число, это число является количеством ветвей процесса.<br><br>Редко, но иногда требуется отключить объединение ветвей, для этого можно использовать ключ <strong>-c<br><br></strong><pre>pstree -c<br><br></pre>Ну и конечно же с помощью ключа <strong>-p</strong>, можно вывести список PID’ов и PGI’ов и потом их жёстко закилить.<br><br><pre>pstree -p<br><br></pre>Есть еще крутая фишка, это ключ <strong>-a</strong>, с помощью него можно получить параметры конфигурации запущенных приложений. То есть допустим запущен у меня какой-то prometheus экспортер и мне надо знать с какими параметрами он запущен, выполняем:<br><br><pre>pstree -a<br><br></pre>и получаем:<br><br><pre>nginx_exporter -nginx.scrape-uri http://localhost/nginx_status<br><br></pre>Сказка, а не утилита! Лично для меня проще запустить <strong>pstree</strong> и не приседать вокруг <strong>ps</strong> со всеми его ключами и наворотами, грепая и страдая. Глянул на дерево визуально и понял, что php, nginx, mysql запущены, значит проблему надо искать в другом месте.<br><br><strong>pstree</strong> входит в пакет psmisc, установка стандартная <code>apt install psmisc</code>, для остальных дистрибутивов аналогично <code>yum/pacman/другое</code>, но в osx без проблем поставилась через <code>brew install pstree</code>, короче тут индивидуальный подход.<br><br><em>если вкатит, можешь запустить pstree --help и глянуть на что она еще способна, там и подсветка и танцы под гитару и жаркие африканские женщины </em><em>💃</em><em><br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-7">

      <div class="body details">
2 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message24">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.07.2023 15:02:18 +07">
15:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_5@02-07-2023_15-02-18.jpg">

         <img class="photo" src="photos/photo_5@02-07-2023_15-02-18_thumb.jpg" style="width: 260px; height: 130px"/>

        </a>

       </div>

       <div class="text">
<strong>nethogs</strong> - одна из большинства программ для мониторинга сети в linux системах. Но среди других она выделяется тем, что можно в режиме реального времени отследить процесс и источник которые генерируют много трафика и забивают канал.<br><br>Установка стандартная: <code>apt/yum/brew install nethogs</code> но если ты упоротый админ, можешь из <a href="https://github.com/raboof/nethogs">исходников</a> собрать и ядро пропатчить <a href = "video_files/sticker.webm">🔨</a><br><br>Я использую <strong>nethogs</strong> довольно редко, но метко. В последний раз была ситуация, когда ко мне пришел Selectel и попросил разобраться почему мы начали превышать полосу пропускания и наш канал несколько дней забит на 200%.<br><br>С помощью <strong>nethogs</strong> это быстро удалось вычислить, утилита показала с какого айпишника протекает и куда вытекает, далее выяснили что наша система синхронизации rclone сошла с ума и гнала терабайты данных со стораджа и прямиком в облачное хранилище.<br><br>Так же у <strong>nethogs</strong> есть различные ключи для запуска, но я ими никогда не пользуюсь, всё и так понятно без всяких надстроек и тюнинга.<br><br>Именно поэтому я тащусь от подобных утилит, где ничего не нужно конфигурировать и по факту получаешь необходимую информацию для дальнейшего дебага.<br><br><strong>Что можно выделить по параметрам запуска<br><br></strong>1. Выставляем время обновления в секундах (по умолчанию 1 секунда)<br><br><pre>nethogs –d 5<br><br></pre>2. Посмотреть сколько процесс передает в мегабайтах, а не его скорость (0 = KB/s, 1 = total KB, 2 = total B, 3 = total MB)<br><br><pre>nethogs –v 3<br><br></pre><em>но можно этого добиться и без параметров, после запуска nethogs, нужно нажать букву m и отображение поменяется, удобно<br><br></em>3. Так же возможно мониторить отдельные интерфейсы<br><br><pre>nethogs eth0<br>nethogs wlan0<br><br></pre>4. Ну и как вишенка, в nethogs есть режим трассировки, запускается с ключом -t<br><br><pre>nethogs -t<br><br></pre><em>Кстати если перевести nethogs на русский язык, то дословно получается что программа называется: «сетевая свинья» ну или «сетевой боров/кабан». Название безусловно интересное, я не знаю что ты будешь делать с этой информацией, просто живи с ней ))<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-8">

      <div class="body details">
3 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message25">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="03.07.2023 15:50:24 +07">
15:50
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Мало кто знает об этой фишке в journalctl, ща расскажу…<br><br>Короче допустим у тебя есть какой-то микросервис или скрипт, который пишет в системный журнал какие-то события или ошибки. К примеру у меня есть bash скрипт, который запускается по крону каждую минуту:<br><br><pre>if [[ &quot;$THREADS&quot; -ge &quot;500&quot; ]]; then<br>   logger &quot;MYSQL THREADS OVERLOAD:&quot; $THREADS<br>fi<br><br></pre>Суть скрипта заключается в том, чтобы мониторить число тредов в mysql, если тредов больше 500, то в системный журнал пишется фраза «MYSQL THREADS OVERLOAD»<br><br>Далее у меня есть еще один bash скрипт, так же запускается раз в минуту:<br><br><pre>TH=$(journalctl -S -180s | grep -c &apos;MYSQL THREADS OVERLOAD’)<br><br>if [[ &quot;$TH&quot; -ge &quot;3&quot; ]]; then<br> systemctl reboot mysql<br>fi<br></pre>   <br>Этот скрипт читает системный журнал и проверяет, если за <strong>три</strong> минуты в журнале проскочила <strong>трижды</strong> (либо больше) фраза «MYSQL THREADS OVERLOAD», то запускается полезная нагрузка, в данном примере у меня ребутится mysql.<br><br>Этот способ можно адаптировать под любые задачи и сделать быстрый мониторинг с оповещением в слак/телеграм.<br><br>Костыльно? ОЧЕНЬ! Я даже не представляю сколько сейчас людей перевернулось в гробу. <a href = "video_files/sticker (1).webm">🤣</a><br><br>Но когда под рукой нет поднятой связки prometheus + grafana + alertmanager, а заказчик требует сделать быстро и срочно, пойдёт и такое решение. Главное чтобы все были довольны.<br><br><em>Кстати я как-то встречал у клиента подобный самописный мониторинг, он нарочно отказался от всех этих модных штук в пользу — чем проще система, тем меньше отказов. Доля правды в этом есть, ну как говорится — каждому свой костыль и велосипед.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-9">

      <div class="body details">
4 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message26">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="04.07.2023 15:03:04 +07">
15:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Будем расширять границы контента. Ща покажу магию, знать это мастхэв. Мотай на ус, если не <s>индус</s> знал, пригодится.<br><br>У нас в компании достаточно банальная инфраструктура, в которую входит балансировщик и несколько нод на которых крутится nodejs приложение с 3000м портом, короче говоря апиха.<br><br><pre>bashdays-b1:443<br>  -&gt; bashdays-w1:3000<br>  -&gt; bashdays-w2:3000<br>  -&gt; bashdays-w3:3000<br>  -&gt; bashdays-w4:3000<br><br></pre>К примеру от клиентов идут POST запросы к апихе, запросы попадают на сервер b1, затем nginx распределяет запросы по нодам w1-w4 и отдает в ответ json. Примитивная балансировка нагрузки, но достаточно стабильная.<br><br>В какой-то момент мне необходимо добавить еще одну ноду с новой версией nodejs приложения.<br><br>Назовем её <code>bashdays-w5</code>. Эта нода не должна обслуживать клиентов, но должна отдавать данные тестировщикам, чтобы те могли потыкать и протестировать в условиях продакшена. Ну а ты как думал? Тестируем на проде, можем себе позволить ))) <a href = "video_files/sticker (2).webm">🎉</a><br><br><strong>Городим в nginx на b1 такой велосипед:<br><br></strong><pre>map $http_x_backend $backend {<br>    bashdays-w5 192.168.0.5:3000; # w5<br>    default backend;<br>}<br><br>upstream backend {<br>  server 192.168.0.1:3000; # w1<br>  server 192.168.0.2:3000; # w2<br>  server 192.168.0.3:3000; # w3<br>  server 192.168.0.4:3000; # w4<br>}<br><br>location / {<br>  add_header X-Upstream $upstream_addr;<br>  proxy_pass http://$backend;<br>}<br><br></pre>Объясняю что происходит, клиенты идут на b1 и попадают по умолчанию в upstream backend, где прописаны ноды w1-w4.<br><br>Тестировщики подставляют заголовок <code>X-Backend: bashdays-w5</code> в своих запросах и попадают на w5. То есть для обычных пользователей ничего не изменилось, но QA теперь с помощью заголовка <code>X-Backend: bashdays-w5</code> могут попасть на новую ноду и затыкать ее хоть до усрачки.<br><br>В location есть директива <code>add_header X-Upstream</code>, она выведет в ответе nginx на какую ноду ты попал, удобно для дебага.<br><br>В раздел map можно добавить еще кучу нод, которые не будут участвовать в обслуживании клиентов, но ты в любой момент сможешь на них попасть с помощью заголовка.<br><br>Если у тебя не апиха, а веб приложение, можешь воспользоваться плагином ModHeader, есть для <a href="https://addons.mozilla.org/ru/firefox/addon/modheader-firefox/">фокса</a> и <a href="https://chrome.google.com/webstore/detail/modheader-modify-http-hea/idgpnmonknjnojddfkpgkljpfnnfcklj?hl=ru">хрома</a>. В нём можно легко подставить все необходимые заголовки и попасть <s>в жопу пальцем</s> туда куда тебе нужно, или не нужно.<br><br><em>Конфигурация nginx это как стихи писать, есть какие-то базовые слова и правила, но в большинстве случаев 90% функционала вообще не используется. Потому что, документацию никто не читает и люди делают так, как научились или подсмотрели на stackoverflow. Вот такие пироги.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-10">

      <div class="body details">
5 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message27">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.07.2023 18:01:36 +07">
18:01
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сегодня я снова научу тебя <s>плохому</s> <strong>хорошему</strong>. Про prometheus я думаю все знают. Но не все знают, что на bash можно за несколько минут написать собственный экспортер метрик. Дада, ты не ослышался — не обязательно быть golang сеньором, чтобы делать крутые и полезные штуки. Погнали чо!<br><br>У prometheus есть основной экспортер <strong>node_exporter</strong>, который собирает 100500 метрик с хоста. Ставится отдельно и элементарно.  Гугол тебе подскажет. У меня он установлен везде где хоть что-то напоминает linux. Короче бест-практик. <br><br>Эт я к чему. У node_exporter есть прекрасный ключик <code>--collector.textfile.directory</code>. Из коробки он не прописан в systemd, поэтому нужно самостоятельно прописать руками в файле <code>/etc/systemd/system/node_exporter.service</code> (у тебя может называться по другому).<br><br><pre>ExecStart=/usr/local/bin/node_exporter --collector.textfile.directory /tmp/textfile_collector<br><br></pre>Суть такая, указываем ему директорию, которая будет регулярно опрашиваться на наличие <code>.prom</code> файлов. Соответственно эти <code>.prom</code> файлы мы будем генерировать с помощью bash скрипта, который засунем в крон. Файл представляет собой текстовый документ в определенном <a href="https://prometheus.io/docs/instrumenting/exposition_formats/">формате</a>.<br><br>А далее все нужные нам метрики попадут автоматом в prometheus, а там глядишь и в grafana красиво всё станет.<br><br>Лепота! <a href = "video_files/sticker (3).webm">🫥</a><br><br>Покажу на примере моего скрипта, который забирает количество оставшихся писем в квоте по API с почтового сервиса smtp и передает напрямую в prometheus.<br><br><pre>#!/bin/bash<br><br>MAINDIR=/tmp/text_collector<br>METRICS=smtp.prom<br><br>rm $MAINDIR/$METRICS<br><br>count=$(curl -s -X GET &quot;https://api.smtp/v1/user&quot; -H &quot;accept: application/json&quot; -H &quot;Authorization: superapipassword» | jq &apos;.quota&apos;)<br><br>echo &quot;smtp_quota{service=\&quot;smtp_exporter\&quot;} &quot;$count &gt;&gt; $MAINDIR/$METRICS<br><br></pre>Кидаем его в крон <code>*/1 * * * *</code> и на выходе получаем в папке <code>/tmp/text_collector </code>файл smtp.prom в котором будет нечто подобное:<br><br><pre>smtp_quota{service=&quot;smtp_exporter&quot;} 26818<br><br></pre>И это всё! Готовый экспортер на коленке за несколько минут! Все данные по квоте теперь лежат в параметре smtp_quota. А дальше выводим графики, ставим алерты, балдеем. <br><br><em>С помощью curl и jq можно парсить вообще всё что угодно и запихивать в prometheus, пусть страдает, он для этого и был создан! Ну а больше инфы по ключикам node_exporter можешь получить </em><a href="https://github.com/prometheus/node_exporter">тут</a><em>, может чего еще интересного откопаешь и с нами поделишься.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;monitoring&quot;)">#monitoring</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-11">

      <div class="body details">
6 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message28">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.07.2023 17:53:39 +07">
17:53
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сегодня мы будем делать с вами свой <strong>nginx plus</strong> (тот который платный), а именно реализуем плюшку «<strong>Active health checks</strong>».<br><br>Это когда у тебя к примеру 10 апстримов и если один из них дохнет, то какой-нибудь богатый клиент получит 502 ошибку, обозлится и ничего не купит. А должен автоматически попасть на другой, более живой апстрим и потратить денежку.<br><br>Само собой будем применять инновационные технологии и немного возьмем из фреймворка «гавно и палки». Ну а как ты хотел? Бест практик! На халяву и уксус сладкий, как говорится. Короче все элементарно. Погнали.<br><br>Ставим ванильный nginx и делаем так:<br><br><pre>upstream backend {<br>    server unix:/var/run/haproxy/backend.sock;<br>}<br><br>location / {<br>  proxy_pass http://backend;<br>}<br><br></pre>Ставим рядом haproxy, и конфигурируем блоки frontend и backend таким образом:<br><br><pre>defaults<br>  retries 3<br>  timeout check 5s<br>  <br>frontend bashdays-backend<br>  bind /var/run/haproxy/backend.sock user nginx mode 600<br>  mode tcp<br>  default_backend bashdays-backend<br>  option tcplog<br><br>backend bashdays-backend<br>  balance roundrobin<br>  option tcplog<br>  server bashdays-w1 192.168.0.1:80 check<br>  server bashdays-w2 192.168.0.2:80 check<br>  server bashdays-w3 192.168.0.3:80 check<br>  server bashdays-w4 192.168.0.4:80 check<br><br></pre>Что это за хрень, щас объясню. Смотри. Клиент идет на <s>хуй</s> корень / и попадает в nginx апстрим backend, а апстрим сконфигурирован на сокет backend.sock от haproxy.<br><br>Далее запрос клиента пролетает по сокету, как фанера над загнивающим парижем и попадает в блок haproxy «backend» где у меня описаны все бэкенд-сервера (w1, w2, w3, w4).<br><br>Если по какой-то причине к примеру сервер w2 отдаст концы, haproxy это задетектит (timeout  check 5s) и закинет запрос клиента на рабочий инстанс, тем самым клиент получит статус 200. А 200 == <s>заебись</s> хорошо! <a href = "video_files/sticker (4).webm">🗒</a><br><br>Ну а потом когда w2 очухается, то haproxy снова заберет его в свои сети и будет использовать на всю катушку, как провинившуюся падшую женщину.<br><br>Вот так это и работает. Вот так вот и живем. Балансировка нагрузки + roundrobin + active health checks<br><br><em>У haproxy еще есть встроенный визуальный мониторинг, но об этом я расскажу тебе в одной из следующих статей. <br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-12">

      <div class="body details">
7 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message29">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.07.2023 17:49:40 +07">
17:49
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
С пятницей коллеги! Сегодня на повестке у нас еще одна полезная тулза.<br><br><strong>PV</strong> «pipe viewer», держу пари многие даже и не подозревали что такое существует. <br><br>Что же она делает? Давай на пальцах, когда ты запускаешь из консоли дампиться базу или выполняешь копирование какого нибудь большого файла, ничего не остается кроме как красноглазить и ждать конца операции. На экране нет никакой полезной информации. <br><br>Ну дак вот, встроив в свой pipe эту утилиту у тебя появится информативный progress bar который в реальном времени будет показывать cкорость обработки данных.<br><br><pre>[===&gt;xxxxxxxx] 20%<br><br></pre>Пошли тыкать:<br><br><code>pv /var/log/php/php-fpm.log | gzip &gt; php-fpm.gz<br><br>33MiB 0:00:03 [ 114MiB/s] [==========&gt;    ] 32% ETA 0:00:06    </code>                                                                                       <br><br>Наглядно видно, что через пайп за 3 секунды прошло 33Мб — это 32% от всего объема, операция займет еще 6 секунд. <s>Заебись!</s> Хорошо! <a href = "video_files/sticker (5).webm">😏</a><br><br><strong>PV</strong> это вовсе не <code>cat</code>, её возможности намного шире, тут уже зависит на сколько ты будешь оригинален в своих скриптах и велосипедах.<br><br>Утилита укомплектована внушительной кучей различных ключей для запуска. Но я не привередливый и пользуюсь ей исключительно функционалом из коробки. Если есть время, кури <code>--help</code> или можешь глянуть на доисторической официальной <a href="https://sourceforge.net/projects/pipeviewer/">страничке</a>, а при желании и скомпилировать. <br><br>Из клёвых ключей, есть:<br><br><pre>-l строчный режим, pv может ограничивать скорость и просто в байтах<br>-L 100 – необходимое ограничение<br><br></pre>Допустим у тебя есть база данных, которая не толерантна к большому объёму INSERT-ов и UPDATE-ов. Но у тебя также есть большой дамп с кучей таких операций.<br><br><strong>Как безопасно импортировать дамп в базу и не убить её нахуй?</strong> А вот так:<br><br><pre># скорость ограничена 100 тысячами строк в секунду<br>pv -L 100k -l dump.sql | mysql -u root -p<br><br># скорость ограничена 100 строками в секунду<br>pv -L 100 -l dump.sql | mysql -u root -p<br><br></pre>Ну и на закусочку, баянище:<br><br><code>pv /dev/urandom &gt; /dev/null<br>23MB 0:00:05 [ 12,9MB/s] [...&lt;=&gt;..........]<br><br></code><em>Не болей и береги себя. Всем хороших предстоящих выходных. Тут еще столько всего неизвестного и полезного ожидает тебя</em>, <em>мама не горюй )))<br><br>Увидимся в понедельник!</em> <a href = "video_files/sticker (6).webm">💛</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-13">

      <div class="body details">
10 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message30">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.07.2023 15:34:24 +07">
15:34
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ну что ж, надеюсь ты успел отдохнуть и готов к новым приключениям. Сегодня мы с тобой реализуем собственный конфиг-агент. Естественно применим самые наилучшие практики, естественно на bash. Поехали.<br><br><strong>Что такое конфиг-агент?</strong> Это такой механизм, который держит конфиги на сервере в актуальном состоянии. К примеру какой-нибудь <s>мудень</s> плохой человек с бодуна накосорезил и грохнул важный nginx файл с апстримами, а вернуть как было не может, нет знаний, нет головы, нет бекапов, нет будущего.<br><br><em>Ты спросишь? А какого хуя? Как так получилось? А вот так, порой у тестировщиков есть root на тестовые машины, чтобы они не дергали девопсов, а могли сами зайти на свой сервер и подебажить проект. Но дебаг может затронуть nginx, php и т.п. конфиги. Лезут же куда не попадя, все хотят быть крутыми девопс инженерами.<br><br></em>В этом случае нас спасет конфиг-агент, который автоматически придет через минуту, заберет эталонные конфиги из git, всё красиво восстановит и передернет на Билли Айлиш.<br><br>Ясно дело можно через ansible и puppet все это провернуть, но слишком избыточно, это то же самое, что поднять kubernetes и крутить в нем личный бложек на wordpress, ну такое… <br><br>Не унывай, выход есть! Это можно реализовать за несколько минут и потом снова пару недель пинать <s>хуи</s> воздух. Главное на планировании спринта сказать — я оцениваю эту задачу в 14 дней. <a href = "video_files/sticker (7).webm">😘</a><br><br>Как я раньше и сказал, есть некий git репозиторий где хранятся все эталонные конфиги. Все изменения в конфигах производятся через этот репозиторий.<br><br>На примере покажу как мониторить nginx конфиги и сделать простенький агент. Дальше уж сам свой велосипед под свои реалии запилишь.<br><br><strong>Практика</strong> <em>(упрощаю до минимума, чтобы ты понял смысл)<br><br></em>Закидываем файл<code> /usr/local/sbin/config-agent.sh</code> делаем ему <code>chmod +x</code> (чтобы он был исполняемым) и ставим его в крон <code>*/1 * * * *<br><br>#!/bin/bash<br><br>DIR=/tmp/nginx-configs<br><br>if [ ! -d &quot;$DIR&quot; ];<br>then<br>   git clone git@git.bashdays.ru:dev/nginx-configs.git /tmp/nginx-configs<br>fi<br><br>cd /tmp/nginx-configs &amp;&amp; git pull --quiet<br>RSYNC=$(rsync -aizh /tmp/nginx-configs/ /etc/nginx)<br><br>if [ $? -eq 0 ]; then<br>  if [ -n &quot;${RSYNC}&quot; ]; then<br>    systemctl reload nginx<br>  fi<br>else<br>  exit 0<br>fi<br><br></code><strong>Давай смотреть что тут происходит</strong>:<br><br>1. Создаем отдельную папку если ее нет в <a href="" onclick="return ShowBotCommand(&quot;tmp&quot;)">/tmp</a><br>2. Клонируем в нее эталонные конфиги с git репозитория<br>3. Переходим в папку и забираем последние изменения<br>4. С помощью rsync, синкаем эталон в папку /etc/nginx<br>5. Если файлы заменились в /etc/nginx то делаем reload<br><br>Всё!<br><br>Знак <code>$?</code> используется для поиска возвращаемого значения последней выполненной команды. <br><br>Теперь у нас есть полный контроль от кривых рук. Ну а чтобы изменить какой-то конфиг, нужно заморочиться и сделать это через  git репу со всеми вытекающими кодревью и т.п.<br><br><em>Как говорится - на bash’ке моей горшок, а в кармане пирожок!<br><br></em>Всем хорошего понедельника коллеги!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-14">

      <div class="body details">
11 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message31">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.07.2023 14:58:26 +07">
14:58
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Солнце палит, а мы пашем, вот такая доля наша.<br><br></strong>Хелло май диа френдз. Сегодня <s>попиздим</s> поговорим про логирование и cron.<br><br>Но поговорим не про системное логирование процесса <strong>crond</strong>, а про более развернутое. Развернем наизнанку, кровь кишки, как ты любишь...<br><br>К примеру у тебя есть консольное приложение, после запуска которого, на экран выводится какой-либо результат.<br><br>Всё хорошо когда запустил ручками и посмотрел. Словил ВАУ эффект! Но если повесить эту задачу на cron, то в системном журнале ты увидишь лишь дату и время запуска.<br><br><pre>Jul 11 00:00:01 bashdays CRON[123456]: (user) CMD (/var/www/htdocs/bin/console export:users)<br><br></pre>Пожалуй очень информативно, правда? Ну запустился, а что произошло внутри, <s>хуй</s> пёс его знает.<br><br><strong>Щас исправим и получим красивое</strong>. Достаточно в конец команды добавить:<br><br><code>&gt;&gt; /var/log/cronlogs/www-console.log<br><br></code>тип того:<br><br><pre>* */1 * * * php /var/www/htdocs/bin/console export:users &gt;&gt; /var/log/cronlogs/www-console.log<br><br></pre>Теперь весь выхлоп с команды <code>console export:users</code> будет аккуратненько логироваться в файл <code>www-console.log</code>. По итогу в файле получаем красоту:<br><br><em>Папку только не забудь создать в /var/log, а то оно дурное и не додумается само.<br><br></em><pre>[2023-07-11 10:04:20] service.stats.INFO: Processing users<br>[2023-07-11 10:04:20] service.stats.INFO: Updating local stats<br>[2023-07-11 10:04:20] service.stats.INFO: Updating count users<br>[2023-07-11 10:04:26] service.stats.INFO: Updating total stats<br>[2023-07-11 10:04:26] service.stats.INFO: Export Success<br><br></pre>По желанию грепаем нужное нам, ну и всегда остаемся в курсе событий, зная что же происходит под капотом. Кстати отлично помогает при дебаге. То что кроновская задача выполнилась, еще ни о чем не говорит, внутри может быть злобный эксепшен <a href = "video_files/sticker (8).webm">😡</a><br><br>Да и не забываем накинуть <strong>logrotate</strong>, чтобы место на диске не сжирало бигдатой, а лучше сразу перенаправляй это дело в какой-нибудь агрегатор логов типа ELK или LOKI.<br><br>Бонусом лови конфиг для <strong>logrotate</strong>, чтоб в гугле не лопатить:<br><br><pre>/var/log/cronlogs/www-console.log {<br>   su root root<br>   daily<br>   missingok<br>   rotate 14<br>   compress<br>   notifempty<br>   sharedscripts<br>}<br><br></pre><strong>Есть ли другие способы мониторинга для подобных ситуаций?</strong> Конечно есть! Но способ который я описал выше, используется практически всеми. По крайней мере я на него натыкаюсь постоянно у ребят в различных компаниях.<br><br>Потому что люди не любят усложнять и предпочитают быстренько наговнокодить, получить желаемый результат и дальше смотреть свои любимые сериальчики и <strong>наши мемчики</strong> <a href="https://t.me/+ZAWUP4vMH5Y4Mjcy">тут</a> и <a href="https://t.me/+Z1F7oSfBXYc4MTVi">тут</a>.<br><br><em>О других способах я обязательно напишу отдельный пост, пусть это будет интригой, ну а может ты сам загуглишь и нам потом расскажешь.<br><br></em><strong>В общем адью, албибэк, увидимся! </strong><strong>😎</strong><strong><br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-15">

      <div class="body details">
12 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message32">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.07.2023 15:54:24 +07">
15:54
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>А давай заколхозим настоящую базу данных на bash!<br><br></strong>Дада, ты не ослышался, начиная с bash 4.0 можно и такое провернуть. Дай нам палку и гвоздь, а мы сделаем из этого кофеварку, мыж с тобой настоящие инженеры-программисты, фак ее!<br><br>Летсгоу! Есть у меня огромный txt файл со словами, отсортированный по алфавиту. Нет, не словарь для брутфорса <a href = "video_files/sticker (9).webm">🍸</a><br><br>Если на него натравить <code>sed</code>, то скорость извлечения нужного слова из файла — ну совсем никакая, сидишь как баран ждешь, пока этот сыщик Коломбо, что-то откроет-отроет. Но в век высокий технологий, скорость как-никак в приоритете. <br><br><em>SED – это потоковый редактор текста (от stream editor), c помощью которого можно выполнять с файлами множество операций вроде поиска и замены, вставки или удаления. При этом чаще всего он используется именно для поиска и замены.<br><br></em>Давай разгонять этого ленивца «Блиц, скорость без границ»<br><br><strong>Каков план:<br><br></strong>1. Отсортировать содержимое txt файла по алфавиту<br>2. Проиндексировать данные<br><br>Так как файл у меня содержит слова (не цифры и т.п.), то индексами я сделаю диапазоны строк начинающихся на определенную букву.<br><br><pre>sort -o data.txt data.txt<br><br></pre>Эта команда отсортирует содержимое файла <strong>data.txt</strong> по алфавиту и перезапишет его в нужном мне формате.<br><br><strong>Пишем код<br><br></strong>Проверяем первый аргумент переданный в скрипт. Если передать что-то кроме букв, то экзитим:<br><br><pre>[[ $1 =~ ^[a-z]+$ ]] || exit<br><br></pre>Берем первую букву из первого аргумента и присваиваем её переменной.<br><br><pre>INDEX=${1:0:1}<br><br></pre>Инициализируем переменную <strong>SEARCH</strong> значением первого аргумента, чтобы нам было удобнее в будущем. Это будет искомым словом по нашей базе.<br><br><pre>SEARCH=$1<br><br></pre>Далее объявляем переменную <strong>DATA</strong>. В которой будет указываться путь до нашего файла. Который мы заранее отсортировали по алфавиту.<br><br><pre>DATA=data.txt<br><br></pre>Объявляем и инициализируем hash ассоциативный массив. <strong>Будет работать начиная с bash 4.0, это важно.<br><br></strong><pre>declare -A HASH=([&apos;a&apos;]=1,1001 [&apos;b&apos;]=1002,2002 [&apos;c&apos;]=2003,3003</pre><code>)<br><br></code><em>Тут я сократил, ниже скрипт полностью.<br><br></em>Здесь можешь ручками заполнить этот хэш, а можешь еще один скрипт написать, чтобы автоматом заполнился. Но проще ручками, чтобы не <s>ебстись</s> тратить время.<br><br><em>Что блять это за хуйня конструкция? Ну смотри, берем индекс [&apos;a&apos;]. В файле data.txt слова начинающиеся c &apos;а&apos; и идут с первой строки до 1001, далее начинаются слова на букву &apos;b&apos; строки 1002-2002, ну и так далее.<br><br>Короче выявляем короткие диапазоны, по которым будем осуществлять дальнейший поиск. Зачем тебе лопатить весь файл, если можно пройтись по нужному диапазону.<br><br></em>Далее отдаём утилите <strong>«sed»</strong> диапазон строк и само искомое слово. В данном примере я делаю два вызова через пайп (pipe), но можно извернуться и обойтись одним.<br><br><pre>sed -n &quot;${HASH[$INDEX]}p&quot; | sed -n &quot;/^${SEARCH}$/{p;q}&quot;<br><br></pre><strong>Весь скрипт будет выглядеть так:<br><br></strong><pre>#!/bin/sh<br><br>[[ $1 =~ ^[a-z]+$ ]] || exit<br><br>INDEX=${1:0:1}<br>SEARCH=$1<br>DATA=path<br><br>declare -A HASH=(<br>[&apos;a&apos;]=1,1001        [&apos;b&apos;]=1002,2002       [&apos;c&apos;]=2003,3003<br>[&apos;d&apos;]=3004,4004     [&apos;e&apos;]=4005,5005       [&apos;f&apos;]=5006,6006<br>[&apos;g&apos;]=6007,7007     [&apos;h&apos;]=7008,8008       [&apos;i&apos;]=8009,9009<br>[&apos;j&apos;]=9010,10010    [&apos;k&apos;]=10011,11011     [&apos;l&apos;]=11012,12012<br>[&apos;m&apos;]=12013,13013   [&apos;n&apos;]=13014,14014     [&apos;o&apos;]=14015,15015<br>[&apos;p&apos;]=15016,16016   [&apos;q&apos;]=16017,17017     [&apos;r&apos;]=17018,18018<br>[&apos;s&apos;]=18019,19019   [&apos;t&apos;]=19020,20020     [&apos;u&apos;]=20021,21021<br>[&apos;v&apos;]=21022,22022   [&apos;w&apos;]=22023,23023     [&apos;x&apos;]=23024,24024<br>[&apos;y&apos;]=24025,25025   [&apos;z&apos;]=25026,26026 )<br><br>sed -n &quot;${HASH[$INDEX]}p&quot; &quot;$DATA&quot; | sed -n &quot;/^${SEARCH}$/{p;q}&quot;<br><br></pre>Ничего сложного, а самое главное мы используем инструменты, которые поставляются из коробки с Linux. Ну и конечно же в несколько тысяч раз повысили и оптимизировали скорость чтения данных из огромного текстового файла.<br><br><em>Не нужно стрелять из пушки по воробьям используя какие-то мастодонтные решения. С помощью гвоздя и палки, можно творить настоящие чудеса.<br><br></em>Надеюсь коллеги вам было интересно, продолжим завтра!<br><br><strong>Show must go on </strong><strong>☺️</strong><strong><br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-16">

      <div class="body details">
13 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message33">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.07.2023 16:44:14 +07">
16:44
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
День сегодня такой длинный, жаркий (+37)... Надеюсь у тебя дела обстоят с этим попроще.<br><br>Поэтому простыней и сложных штук делать не будем, довольствуемся малым, но как обычно полезным.<br><br>Давай напишем <strong>генератор псевдослучайных чисел</strong>. Пригодится для создания всяких секретиков и айдишников в твоих bash скриптах.<br><br><strong>Опа, опа и готово! А ты думал?</strong> <a href = "video_files/sticker (10).webm">😊</a><br><br><pre>echo $(tr -dc 0-9A-Za-z &lt; /dev/urandom | head -c 16)<br><br></pre>На выходе получаем нечто подобное из 16ти символов:<br><br><pre>IioP0zmnPTBOuHqI<br>xhqohdWb0r94w7di<br>yMVEHwU0DCTYaGCq<br>KbLwMB7Iqb28Ud4T<br><br></pre>Ты в праве поменять <code>0-9A-Za-z</code> и оставить к примеру только цифры <code>0-9</code>, ну и соотвественно указать длину получаемой строки <code>-c 16</code>.<br><br>Короче, запрашиваем у устройства <code>/dev/urandom</code> данные (16 случайных символов), скармливаем их <code>tr</code>, приводим в должный вид и получаем ожидаемый результат. Красота!<br><br><strong>Ну и кому интересно, маленько теории по tr и urandom<br><br></strong><em>Команда tr (translate) используется в Linux в основном для преобразования и удаления символов. Она часто находит применение в скриптах обработки текста. Ее можно использовать для преобразования верхнего регистра в нижний, сжатия повторяющихся символов и удаления символов.<br><br>Устройство /dev/urandom это генератор псевдослучайных чисел. Псевдослучайность urandom зависит от системы. Во многих случаях random и urandom генерируют символы по одному и тому же алгоритму.<br><br>Чтение данных устройства /dev/urandom возвратит столько байтов, сколько было запрошено.<br><br></em><strong>Ну и по ключам tr которые использовались.<br><br></strong><code>-c </code>- удалить все символы, кроме тех, что в первом наборе<br><code>-d</code>  - удалить символы из первого набора<br><br>Чтобы это ни значило, это работает. Просто используй <a href = "video_files/sticker (11).webm">😊</a>!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-17">

      <div class="body details">
14 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message34">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="14.07.2023 17:02:02 +07">
17:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ну вот и пятница на носу. Хотя какая разница какой день недели, если ты работаешь 24/7. Чем займёмся сегодня? Давай чём-нибудь простым и интересным.<br><br>Порой необходимо определить <strong>количество ядер на сервере</strong>. Понятно, ты можешь вызвать top/htop и визуально глянуть цифру.<br><br>Но мыж с тобой не пальцем деланные, нам надо всё по уму, как тру программисты. Чтобы можно было это в скрипт засунуть и далее плясать от полученного результата. <a href = "video_files/sticker (12).webm">💃</a><br><br>Для подсчета количества ядер, есть несколько способов:<br><br><pre>1. grep -wc &apos;^processor&apos; /proc/cpuinfo<br>2. getconf _NPROCESSORS_ONLN<br>3. nproc --all<br><br></pre>Это не единственные способы заполучить желаемое, но <strong>самые релевантные</strong>. Кстати <code>getconf</code> актуален и для макаводов (osx).<br><br>Для чего нам знать количество ядер? Вопрос хороший, каждый для себя сам решает. Всё зависит от задач.<br><br>К примеру заскейлил ты тачку в Selectel, через их веб панельку, но nginx продолжает работать на старом конфиге. После этого очень желательно сразу переопределить в <code>nginx.conf</code> параметр <code>worker_processes</code>. <br><br><em>Если Nginx выполняет работу нагружающую процессор (например SSL или gzipping), то оптимально установить эту директиву в значение, равное количеству ядер процессора.<br><br>Также, директива worker_processes, умноженная на worker_connections из секции event, даст максимально возможное количество клиентов.<br><br></em>Конечно же справедливо всё это ансиблом (ansible) или террой (terraform) раскатать, но это дополнительный геморрой, который никому не нужен. По крайней мере, когда это нужно было еще вчера и нет возможности писать лапшу из плейбуков.<br><br>Проще уж из скрипта узнать количество ядер, все посчитать и тем же sed’ом зареврайтить нужный тебе конфиг. Вешаешь его на крон, а оно следит за твоими ядрами и в нужный момент делает всё автоматически, хоть там каждую минуту горизонтально-вертикальным масштабированием занимайся.<br><br><strong>Прототип без ифов, так, для наглядности:<br><br></strong><pre>#!/bin/bash<br><br>CPU_CORES=$(grep -wc &apos;^processor&apos; /proc/cpuinfo)<br><br>sed -i &quot;s/worker_processes.*/worker_processes $CPU_CORES;/&quot; /etc/nginx/nginx.conf<br><br>systemctl reload nginx<br><br></pre>Бери на вооружение, пригодится. <a href = "video_files/sticker (13).webm">😮‍💨</a><br><br>Ну а я желаю тебе хороших предстоящих выходных и береги себя! Мож чо на выходные еще закину интересного почитать.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-18">

      <div class="body details">
17 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message35">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.07.2023 15:55:29 +07">
15:55
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>И снова понедельник и снова на работу.</strong> Привет, коллеги. Надеюсь все живы, здоровы.<br><br>Сегодня начнем потихоньку тыкать полезную утилиту <strong>strace</strong>. Многим она кажется <s>пиздец</s> очень страшной, но на самом деле всё обстоит иначе. Если научишься с ней правильно работать и понимать, сможешь отдебажить любую ошибку и сразу станешь тимлидом, а может быть и техническим директором. <a href = "video_files/sticker (14).webm">😈</a><br><br><em>strace — это утилита, отслеживающая системные вызовы, которые представляют собой механизм трансляции, обеспечивающий интерфейс между процессом и операционной системой/ядром<br><br></em><strong>Ну а если по русски:</strong> это полезный инструмент диагностики и отладки. <br><br>Начнем с простого. Для экспериментов нам понадобится файл <code>HUY.txt</code>, давай создадим его командой:<br><br><pre>echo &apos;12345&apos; &gt; HUY.txt<br><br></pre>Опыты проводим над утилитой <code>sed</code>. Исследовать будем команду:<br><br><pre>sed -i.tmp &apos;s/1/2/&apos; HUY.txt<br><br></pre>Ключ <code>-i</code> означает редактирование файла на месте, принимает необязательный суффикс <code>tmp</code>. Если суффикс задан, то будет создана копия файла с предыдущим содержанием.<br><br>Команда <code>s///</code> это команда замены, одного на другое. То есть в примере мы меняем <code>(1)</code> на <code>(2)</code> в файле <code>HUY.txt<br><br></code><strong>Погнали изучать кишки<br><br></strong><pre>strace -ye &apos;/^open&apos;,read,write,rename,close sed -i.tmp &apos;s/1/2/&apos; HUY.txt<br><br></pre>Выведет <s>дохуя</s> много всего, но ты не ссы, тебе нужно посмотреть только последние несколько строчек. Всё остальное не достойно твоего внимания.<br><br><strong>Посмотрим вывод с момента открытия файла HUY.txt<br><br></strong><pre>1. openat(AT_FDCWD, &quot;HUY.txt&quot;, O_RDONLY)   = 3&lt;/tmp/HUY.txt&gt;<br>2. openat(AT_FDCWD, &quot;./sedvKFsXv&quot;, O_RDWR|O_CREAT|O_EXCL, 0600) = 4 &lt;/tmp/sedvKFsXv&gt;<br>3. read(3&lt;/tmp/HUY.txt&gt;, &quot;12345\n&quot;, 4096)  = 6<br>4. read(3&lt;/tmp/HUY.txt&gt;, &quot;&quot;, 4096)         = 0<br>5. close(3&lt;/tmp/HUY.txt&gt;)                  = 0<br>6. write(4&lt;/tmp/sedvKFsXv&gt;, &quot;22345\n&quot;, 6)  = 6<br>7. close(4&lt;/tmp/sedvKFsXv&gt;)                = 0<br>8. rename(&quot;HUY.txt&quot;, &quot;HUY.txt.tmp&quot;)        = 0<br>9. rename(&quot;./sedvKFsXv&quot;, &quot;HUY.txt&quot;)        = 0<br>10. close(1&lt;/dev/pts/0&gt;)                   = 0<br><br></pre><strong>Теперь разберем построчно, что же произошло</strong>:<br><br>1. Открывается файл <code>HUY.txt<br></code>2. Открывается временный файл <code>sedvKFsXv<br></code>3. Из файла <code>HUY.txt</code> читаются 6 байт <code>12345\n<br></code>4. Пробует прочитать еще раз <code>HUY.txt</code>, вернулось 0 байт, найден конец строки<br>5. Закрывается файл <code>HUY.txt<br></code>6. Записывается 6 байт <code>22345\n</code> во временный файл <code>sedvKFsXv<br></code>7. Закрывается временный файл <code>sedvKFsXv<br></code>8. Переименовывается файл <code>HUY.txt</code> в <code>HUY.txt.tmp<br></code>9. Переименовывается временный файл <code>sedvKFsXv</code> в <code>HUY.txt<br></code>10. Что-то там где-то опять закрывается<br><br><strong>Если подытожить, получилось такое:<br><br></strong>- Считывается исходный файл <code>HUY.txt<br></code>- Во временный файл <code>sedvKFsXv</code> записывается обработанный текст<br>- Исходный файл <code>HUY.txt</code> становится резервной копией <code>HUY.txt.tmp<br></code>- Временный файл <code>sedvKFsXv</code> становится текущим <s>хуем</s> <code>HUY.txt<br><br></code><strong>Что нам дал этот эксперимент?<br><br></strong>А дал он нам то, что <strong>всё работает</strong>. И теперь у нас есть понимание <strong>как это работает</strong>.<br><br>Допустим столкнулся ты с проблемой, что <code>sed</code> не смог что-то записать и ты не понимаешь почему. Запускаешь <strong>strace</strong> и смотришь почему:<br><br><pre>write(4&lt;/tmp/sedvKFsXv&gt;, &quot;strace: exec: Permission denied\n&quot;, 6)  = 6<br><br></pre>Опа, а прав на запись в папку <code>/tmp</code> нет, возможно какой-то лось дырявый запретил туда запись. <strong>Отдебажили, фиксим</strong>: выставляем 3 топора (<code>chmod 777</code>) на папку <code>/tmp</code> и радуемся какие мы молодцы.<br><br>Этот способ отладки ты можешь применить не только для <code>sed</code>, но и для своих скриптов, программ, сервисов и т.п. Как нибудь в будущем поэкспериментируем с php и Битриксом <a href = "video_files/sticker (15).webm">🤡</a><br><br><em>Как-то так. Ничего же сложного? Ну вот и я про тоже. Главное не бояться и знать куда смотреть. Ну а я покажу куда смотреть и проведу тебя протоптанными дорожками.<br><br></em>Ладно, пойду пельмени жарить, всем хорошего понедельника! <a href = "stickers/sticker (18).webp">💗</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-19">

      <div class="body details">
18 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message36">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.07.2023 20:52:56 +07">
20:52
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Как говорит «Камень в лесу» — сегодня ничего не произошло. <br><br></strong>Иногда хочется побыть таким камнем, но не сегодня. Сегодня у нас «<strong>Необычные способы узнать дату и время</strong>»<br><br>Ты скажешь есть же команда <strong>date</strong>, верно, есть и такая. Но мы же с тобой не пальцем деланные, нам надо посложнее, по геморойнее <a href = "video_files/sticker (16).webm">😢</a><br><br>Есть несколько способов узнать из консоли текущую дату и время. К примеру ты можешь сделать это через утилиту <strong>stat</strong>.<br><br><pre>stat -c&apos;%z&apos; /proc/self/stat<br><br></pre>Временные метки [atime, mtime, ctime] будут равны времени создания [inode] для этого «файла». В данном случае это время обращения к данному файлу. Вообще <strong>proc</strong> сама по себе интересная штука. Почти для каждого файла есть свой набор функций для стандартных операций [read, write, open и т.п.].<br><br><s>Нихуя</s> Ничего не понял? Забей, просто знай что команда <strong>stat</strong> выведет тебе текущую дату и время.<br><br><pre>2023-07-18 11:42:22.592640126 +0000<br><br></pre><strong>А еще получить желаемое можно с помощью утилиты «ps</strong>»<br><br><pre>ps --no-headers -o lstart -C ps<br><br></pre>Время и дата равны времени запуска процесса ps<br><br><pre>Tue Jul 18 11:44:07 2023<br><br></pre><strong>Следом идет команда «printf</strong>»<br><br><pre>printf &apos;%(%c)T\n&apos;<br><br></pre>Это встроенная команда в оболочку Bash. Выводится дата и время в соответствии с установленной локалью.<br><br><pre>Tue Jul 18 11:44:53 2023<br><br></pre><strong>А еще можно так:<br><br></strong><pre>( T=&apos;\t&apos; ; echo ${T@P} )          <br>( T=&apos;\T&apos; ; echo ${T@P} )<br>( T=&apos;\@&apos; ; echo ${T@P} )<br>( T=&apos;\A&apos; ; echo ${T@P} )<br>( T=&apos;\D{%X%t%x}&apos;; echo ${T@P} )<br><br></pre><code>${parameter@P}</code> начиная с версии bash 4.4<br><br><pre>16:16:22<br>04:16:26<br>04:16 PM<br>16:16<br>16:16:39 07/18/23<br><br></pre>Ну и фаталити на закусочку, выведем unixtime тремя разными способами. Эквивалентно команде: <code>date &apos;+%s&apos;<br><br></code><pre>printf &apos;%s\n&apos; &quot;$EPOCHREALTIME&quot; <br>printf &apos;%s\n&apos; &quot;$EPOCHSECONDS&quot;<br>printf &apos;%(%s)T\n&apos;<br><br>1689686418.954954<br>1689686418<br>1689686418<br><br></pre><em>Вообще редко такое может пригодиться, но пару раз на собесах какие-то упоротые техдиры задавали подобный вопрос. Не знаю откуда они такое берут, но факт остается фактом.<br><br></em>Разнообразь свои скрипты такими замысловатыми конструкциями и ни один девопс (кроме тебя естественно) нихрена не поймёт. Создашь басфактор и будешь самым незаменимым в коллективе <a href = "video_files/sticker (17).webm">😠</a> пам пам пам<br><br><strong>Всем добра котики!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-20">

      <div class="body details">
20 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message37">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.07.2023 16:24:47 +07">
16:24
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Есть такая поговорка «<strong>Взял bosch и ебошь</strong>», но у нас, у айтишников эта поговорка звучит немного иначе «<strong>Взял bash и ебашь</strong>». Из песни слов не выбросишь <a href = "video_files/sticker (18).webm">🍴</a><br><br>Команда <strong>history</strong>, это не просто вывод истории команд, которые ты или кто-то набирал в консоли. Это великолепный инструмент, с помощью которого можно воссоздать к примеру всю картину настройки сервера. Либо отдебажить момент когда всё работало, а сегодня перестало, по причине какого нибудь отбитого админа, который решил тонко оптимизировать linux ядро.<br><br>В общем — <strong>history</strong>, это как спасательный круг. Давай сегодня затюним её на удобство.<br><br><strong>Чего же не хватает из коробки?</strong> А не хватает <strong>временны́х маркеров</strong>, то есть даты и времени, когда была выполнена та или иная команда. Это легко решаемо. Для оболочки <strong>bash</strong> это делается так:<br><br><pre>export HISTTIMEFORMAT=&quot;%d/%m/%y %T &quot;<br><br></pre>И вывод будет примерно таким:<br><br><pre>  369  20/07/23 15:46:54 flask run<br>  370  20/07/23 15:46:54 /usr/bin/python3<br>  371  20/07/23 15:46:54 python --version<br>  372  20/07/23 15:46:54 python3 --version<br>  373  20/07/23 15:46:54 ps ax|grep python<br>  374  20/07/23 15:46:54 sudo kill -9 30049<br>  375  20/07/23 15:46:54 brew install pyenv<br><br></pre>Либо можешь прописать это в <code>~/.bashrc</code> чтобы <strong>export</strong> выполнялся автоматически:<br><br><pre>echo &quot;export HISTTIMEFORMAT=\&quot;%d/%m/%y %T \&quot;&quot; &gt;&gt; ~/.bashrc<br><br></pre>Прекрасно, теперь намного нагляднее. Идем дальше. Давай перекрасим временные маркеры в синий цвет, чтобы более лаконично выглядело.<br><br><pre>export MY_BASH_BLUE=&quot;\033[0;34m&quot;<br>export MY_BASH_NOCOLOR=&quot;\033[0m&quot;<br>export HISTTIMEFORMAT=`echo -e ${MY_BASH_BLUE}[%F %T $MY_BASH_NOCOLOR `<br><br></pre>Эти экспорты можешь так же закинуть в <code>~/.bashrc</code> и затем выполнить команду <code>source ~/.bashrc</code> чтобы не перезагружать сессию и применить настройки в моменте.<br><br><strong>Окей, но как же быть с оболочкой zsh? </strong>Сейчас и в ней сделаем нечто подобное.<br><br>Из коробки <strong>zsh</strong>, ты можешь воспользоваться командой:<br><br><pre>history -E<br><br></pre>вывод будет таким:<br><br><pre> 9481  9.5.2023 16:04  export FLASK_RUN_PORT=8888<br> 9482  9.5.2023 16:04  export FLASK_APP=index.py<br> 9483  9.5.2023 16:04  flask run<br> 9484  9.5.2023 16:08  export TGS_API_KEY=12345<br> 9485  9.5.2023 16:08  flask run<br><br></pre>Уже более менее информативно, а если так:<br><br><pre>history -i<br><br></pre>опа-опа-опапа:<br><br><pre> 9481  2023-05-09 16:04  export FLASK_RUN_PORT=8888<br> 9482  2023-05-09 16:04  export FLASK_APP=index.py<br> 9483  2023-05-09 16:04  flask run<br> 9484  2023-05-09 16:08  export TGS_API_KEY=12345<br> 9485  2023-05-09 16:08  flask run<br><br></pre>Видим другой формат даты. Вообще ключей для форматирования даты достаточно много, можешь почитать на досуге если интересно:<br><br><pre>man zshoptions<br>man zshbuiltins<br><br></pre>Ну а чтобы каждый раз не вводить ключи, сделай нужный тебе <strong>alias</strong> в <code>~/.zshrc<br><br></code><pre>alias history=&quot;history -i&quot;<br><br></pre>А еще есть такая утилита как <strong>«fc»</strong>, я думаю большинство про нее вообще ничего не слышали.<br><br><em>fc — unix-утилита, служащая для редактирования списка ранее введенных команд, а также их выполнения.<br><br></em>Вот тебе команда на основе <strong>fc</strong>, которая выведет историю, сразу же с временными маркерами:<br><br><pre>fc -li 100<br><br></pre>Больше уж и сказать нечего, основное разобрали, внедряй.  Еще есть и другие оболочки типа <strong>fish</strong>, но так как я ими не пользуюсь ежедневно, то и рассказывать вам про них сегодня не буду.<br><br><strong>А завтра снова пятница, неделя прям в трубу вылетела. Давайте, увидимся. </strong><strong>🐱</strong><strong><br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-21">

      <div class="body details">
21 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message38">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.07.2023 15:00:49 +07">
15:00
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
В консоли существует неочевидный способ очень удобно вводить многострочные команды либо накидывать скрипты. Ща покажу на котиках.<br><br>Для этого вызывается текстовый редактор указанный у тебя по умолчанию в переменной <code>$EDITOR</code>. Ты снова скажешь — да <s>блять</s> блин! Это надо еще и редактор запускать?<br><br>Да, запускать надо, но для этого из коробки есть <s>охуенный</s> отличный нативный хоткей <code>CTRL+x+e</code> (а в osx кнопка <strong>CTRL</strong> со значком <strong>^</strong>). <br><br><strong>Как нажать CTRL+x+e и не сломать пальцы? </strong>Сначала зажимаешь и удерживаешь <strong>CTRL</strong>, следом жмешь <strong>x</strong> и не отпуская <strong>CTRL</strong> жмешь <strong>e</strong>.<br><br><a href = "video_files/sticker (19).webm">📺</a> Тырым-Пырым и перед тобой уже твой любимый vim/mcedit/nano/другойshit<br><br>Если получил ошибку: <code>External editor requested but $VISUAL or $EDITOR not set</code>. Не расстраивайся, выполни эти команды и у тебя все заработает. Вместо <strong>nano</strong> подставь своё.<br><br><pre>EDITOR=$(which nano)<br>export EDITOR=$EDITOR<br><br></pre>Либо на постоянку добавь в <code>~/.bashrc или ~/.zshrc</code> и не забудь перечитать эти файлы: <code>source ~/.bashrc &amp;&amp; source ~/.zshrc<br><br></code><em>which — команда используется для определения местоположения данного исполняемого файла, который выполняется при вводе имени исполняемого файла (команды) в строке терминала. Команда ищет исполняемый файл, указанный в качестве аргумента, в каталогах, перечисленных в переменной среды PATH.<br><br></em>Есть еще команда <strong>select-editor</strong>, но не везде присутствует, она сразу список всех редакторов выведет в читабельном виде, тебе останется лишь выбрать циферку. Редактор установится глобально в системе без правки <strong>.bashrc/zshrc</strong>.<br><br><strong>Так, ушли от темы</strong>, короче вызвал ты свой любимый редактор и не сломал пальцы. А дальше? А дальше накидываешь в нем скрипт или команды, которые тебе нужно выполнить в оболочке <strong>bash/zsh</strong>.<br><br>Размеренно, удобно, с подсветкой синтаксиса и хоткеев, а если у тебя прокаченный vim, так вообще полноценная IDE получается.<br><br>Накидал? Сохраняешь! Сохраняется по умолчанию во временную папку: <code>/tmp/bash-fc.GpOzlI<br><br></code>И после закрытия, все команды из файла <strong>автоматически</strong> <strong>выполняются</strong>, а временный файл удаляется. Все введенные команды и выхлоп по ним продублируются в консоли. Так что не переживай, ничего не <s>проебешь</s> потеряешь.<br><br>Я частенько пользуюсь этим способом, когда мне нужно к примеру выполнить на сервере 100 команд подряд, просто копипастю копипасту, вызываю <code>CTRL+x+e</code>, вставляю туда свою портянку, сохраняю и иду в кроватку принимать горизонтальные процедуры.<br><br><em>А еще если ввел какую-то длинную команду в консоли и хочешь ее сохранить отдельным скриптом, жмешь хоткей ctrl+x+e и вуаля, открывается редактор и в нем уже вставлена эта команда. Сохраняешь в папке ~</em><a href="" onclick="return ShowBotCommand(&quot;Downloads&quot;)">/Downloads</a><em> и забываешь про этот файл навсегда.<br><br></em>Почему не ansible? Хм, можешь и плейбуки написать. Хозяин барин. Но у нас тут про комфортную работу в консоли. Про ansible тоже посты будут, но попозже.<br><br>Практично, удобно, всё работает из коробки. А мы с тобой такое любим. Вот такие пироги! Ну и <strong>с пятницей друзья</strong>, всем хороших предстоящих выходных, <strong>берегите себя</strong>.<br><br>PS: <strong>Кстати выйти из vi/vim</strong> можно командой <code>:q!</code> Это тебе бонус на всякий случай <a href = "video_files/sticker (20).webm">👋</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-22">

      <div class="body details">
24 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message40">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="24.07.2023 16:03:01 +07">
16:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Порой мне кажется, что в выходные я устаю больше, чем за всю рабочую неделю. Но это скорее психологическая усталость, так как выпадаешь из рабочего ритма/потока и потом сложно обратно запрыгивать. Ладно, у нас тут не кружок психологии. <a href = "video_files/sticker (21).webm">😳</a><br><br><strong>Сегодня на повестке у нас с тобой OOM Killer.<br><br></strong><em>Out of Memory Killer (OOM Killer) – это механизм ядра Linux, который освобождает оперативную память при ее исчерпании за счет принудительного завершения некоторых запущенных процессов.<br><br></em><strong>Погнали разбираться это работает и как его можно обуздать.<br><br></strong>Когда оперативная память в ос linux заканчивается, происходят забавные вещи, ядро вызывает «кракена» <strong>OOM Killer</strong>. В свою очередь «кракен» прогоняет процесс по определенным правилам и убивает его. <br><br>Бытует ошибочное мнение, что <strong>OOM Killer</strong> берет самый жирный процесс и киляет его. Это не так. Создатели этого механизма знатно упоролись.<br><br><strong>OOM Killer</strong> использует достаточно сложный анализ и присваивает каждому процессу <strong>очки негодности</strong> (<strong>badness</strong>). При исчерпании памяти, будет убит именно самый негодный процесс. Некий естественный отбор. Процесс убивается сигналом <strong>SIGKILL</strong> и не предоставляет приложению корректно завершиться. Вызывается функция <strong>out_of_memory</strong>, а далее <strong>select_bad_process</strong>.<br><br>После убийства, в системном журнале появится строчка:<br><br><pre>Out of Memory: Killed process 2256 (mysql) score 907 or sacrifice child<br><br></pre>А это уже не шутки. Если к тебе стал приходить <strong>OOM Killer</strong>, значит в какой-то момент на сервере, что-то <s>пошло по пизде</s> не так и нужно разобраться.<br><br><strong>Очки негодности</strong> могут принимать значение от <strong>-1000</strong> до <strong>+1000</strong>. Соответственно чем выше это значение, тем вероятнее, что процесс будет убит. А процесс со значением <strong>-1000</strong> будет по логике — бессмертным. <br><br>Посмотреть репутацию процесса, можно командой:<br><br><pre>cat /proc/&lt;PID&gt;/oom_score<br><br></pre><em>Где PID это идентификатор процесса, узнать можешь командой ps ax|grep postfix<br><br></em>В результатах ты увидишь число, к примеру: <strong>826</strong>, это и есть очки негодности.<br><br><em>Если интересно как начисляются очки негодности, я вынес это в отдельный пост в телеграф, чтобы не валить тебя скучной теорией. Почитать можешь тут:<br><br></em><a href = "stickers/AnimatedSticker (2).tgs">✅</a><a href="https://telegra.ph/Kak-rabotaet-OOM-Killer-07-24"> Как вычисляются очки негодности?<br><br></a><strong>TL;DR Если подытожить, то OOM Killer убьет самый «жирный» процесс, который наименее активен в системе и имеет самое короткое время жизни.<br><br>Как обуздать OOM Killer?</strong> <a href = "video_files/sticker (22).webm">🔪</a><br><br>Можно вообще его отключить! Но по понятным причинам, это все равно что отключить жизненно важный орган у человека. Какое-то время он еще проживет, но потом обязательно сдохнет в <strong>kernel panic</strong>.<br><br><strong>Отключается командой:<br><br></strong><pre>sudo echo 1 &gt; /proc/sys/vm/panic_on_oom<br><br></pre>По умолчанию <strong>0</strong> (то есть включено). Я ни разу не встречал, чтобы кто-то отключил этот функционал, но достаточно много раз сталкивался с забиваем костылей в сами процессы.<br><br>Можно повысить или понизить репутацию для процесса, добавив в файл <strong>oom_adj</strong> значение от <strong>-17</strong> до <strong>+15</strong>. Для повышения репутации выполняем команду:<br><br><pre>sudo echo -6 &gt; /proc/&lt;PID&gt;/oom_adj<br><br></pre><em>Не забываем подставить в PID, идентификатор нужного процесса.<br><br></em>Для отключения <strong>OOM Killer для определенного процесса</strong>, выставляем репутацию <strong>-17</strong>. Теперь этот процесс в «домике» и его никакая собака не посмеет тронуть.<br><br><pre>sudo echo -17 &gt; /proc/&lt;PID&gt;/oom_adj<br><br></pre>Но если ты рестартанешь процесс, у него изменится PID. А репутация, которую ты ему уже накрутил, может примениться к совсем другому процессу таким же PID.<br><br>Также можно динамически определять PID процесса и менять ему репутацию. Закинуть это в крон и прыгать от счастья:<br><br><pre>pgrep -f &quot;/usr/sbin/sshd&quot; | while read PID; do echo -17 &gt; /proc/$PID/oom_adj; done<br><br></pre>Но правильнее задать очки в самом systemd, в юните для сервиса, этот параметр:<br><br><pre>[Service]<br>OOMScoreAdjust=-500<br><br></pre><strong>Собственно это база.</strong> <em>По опыту скажу так — если к тебе пришел OOM Killer, сервак можно смело перезагружать. Нихрена там уже не работает, несмотря на всякие очки и коэффициенты. Перезагрузиться будет намного эффективнее, чем пытаться поднять что-то. Поднял, а потом уже по горячим следам и логам, дебаж.<br><br></em><strong>Поздравляю, ты только что прокачался еще на один уровень.</strong> Хорошего тебе понедельника, да и лёгкой рабочей недели! Увидимся! <a href = "video_files/sticker (23).webm">🐾</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-23">

      <div class="body details">
26 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message41">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.07.2023 15:06:45 +07">
15:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>День прошел, число сменилось нихуя ничего не изменилось.</strong> Привет, коллеги!<br><br>Как-то года 3 назад мы настолько устали каждую неделю ремонтировать маунтшары через <strong>glusterfs</strong>, что было принято решение выкинуть его <s>нахуй</s> и пойти в сторону упрощения. Много что попробовали, но остановились на <strong>sshfs</strong>.<br><br><em>GlusterFS — это распределённая, параллельная, линейно масштабируемая файловая система с возможностью защиты от сбоев</em>. <strong>НУ-НУ </strong><a href = "video_files/sticker (24).webm">😠</a><br><br><em>SSHFS — это клиентская программа для Linux, используемая для удаленного управления файлами по протоколу SSH таким образом, как будто они находятся на локальном компьютере.<br><br></em><strong>По вводным:</strong> у нас есть baremetal сервер с огромными HDD дисками на овер 500 терабайт. На диске хранится статика, которую отдаем через nginx. <strong>Задача</strong>: подключать этот диск в облачную инфраструктуру к различным нодам. <strong>Условия</strong>: чтобы работало и не воняло. <a href = "stickers/sticker (19).webp">🤒</a><br><br>Тут все достаточно просто. Даем команду на нужной нам ноде и шара монтируется в папку <code>/mnt/storage</code>:<br><br><pre>sshfs -o compression=no,allow_other,reconnect storage@bashdayz.ru:/storage /mnt/storage<br><br></pre><code>compression</code> - не использовать компрессию<br><code>allow_other</code> - разрешить доступ к шаре <br><code>reconnect</code> - нативный реконект если шара отвалилась <br><br><strong>Из плюсов:</strong> на baremetal сервере не надо устанавливать никакой дополнительный софт, все работает по протоколу ssh.<br><br><strong>Но есть нюансы</strong>. Допустим если ноду перезагрузить, то всё отвалится. Либо придут сетевые ножницы и оно тоже отвалится. <br><br>Запихать в <strong>fstab</strong> не вариант. Так как на этапе маунта еще нет сети и загрузка сервера просто остановится в попытках примонтировать шару. А ключик reconnect работает как ему захочется, даже если выставить таймауты проверок.<br><br><strong>Решение простое, создаем три юнита в systemd</strong>.<br><br><strong>✅</strong><strong> </strong><a href="https://telegra.ph/YUnity-montirovaniya-sshfs-07-26">Первый юнит</a> <em>(АААААРРРРРР!!!!! В пост не влазиет, да и форматирование тут убогое, публикую в телеграфе)<br><br></em><code>After=network.target</code> - запускать маунт только после того, как на хосте поднимется сеть<br><code>What=storage@bashdayz.ru:/storage</code> - что монтируем<br><code>Where=/mnt/storage</code> - куда монтируем<br><br><strong>Важно!</strong> Файл юнита должен называться в соответствии с путем куда монтируем. Узнать имя можно командой:<br><br><pre>systemd-escape -p /mnt/storage<br><br></pre><strong>Первый юнит сохраняем сюда:</strong> <code>/etc/systemd/system/mnt-storage.mount<br><br></code>Теперь нужно сделать юнит проверки, если шара отвалилась. Для начала создаем юнит с таймером:<br><br><strong>✅</strong><strong> </strong><a href="https://telegra.ph/YUnity-montirovaniya-sshfs-07-26">Второй юнит<br><br></a><code>After=mnt-storage.mount</code> - обеспечит запуск таймера после загрузки сервера, но только после того, как маунт юнит будет запущен, то есть после того, как удалённая ФС смонтируется.<br><code>Unit=mnt-storage.service</code> - какой юнит будем запускать при срабатывании таймера. О нём чуть ниже.<br><code>OnCalendar=*-*-* *:*:00</code> - это означает каждую минуту.<br><br>Юнит-файл таймера можно называть как угодно. Но чтобы было понятнее, будем называть также, как и маунт-юнит. Итак, сохраняем в <code>/etc/systemd/system/mnt-storage.timer<br><br></code>Теперь нужно создать юнит, который будет заниматься проверкой маунта и его перезапуском при необходимости:<br><br><strong>✅</strong><strong> </strong><a href="https://telegra.ph/YUnity-montirovaniya-sshfs-07-26">Третий юнит<br><br></a>Здесь всё просто. Bash строка в <strong>ExecStart</strong> это <strong>bash</strong>’евый однострочник, проверяющий наличие маркерного файла <strong>mount.yes</strong>, при отсутствии которого будет перезапущен маунт-юнит. В более новой версии <strong>systemd</strong> можно было бы это всё сделать иначе, но зато такой вариант более универсален.<br><br>Cохраняем в <code>/etc/systemd/system/mnt-storage.service<br><br></code><strong>Релодим и активируем <br><br></strong><pre>systemctl daemon-reload<br>systemctl enable mnt-storage.mount<br>systemctl enable mnt-storage.timer<br><br></pre>Третий юнит <strong>mnt-storage.service</strong> при загрузке сервера активировать не нужно, поскольку этот юнит вызывается таймером <strong>mnt-storage.timer</strong>. Он будет всегда <strong>Active: inactive (dead)</strong>, это нормально.<br><br>Ну и в финале запускаем таймер:<br><br><pre>systemctl start mnt-storage.timer<br><br></pre><strong>Вот и все!</strong> Наша шара успешно взята под контроль, подключена. А в случае отвала по любым причинам, она сама перемонтируется без лишних вопросов. Ну и после перезагрузки ноды, тоже все поднимется из коробки.<br><br>Способ рабочий, полет стабильный более трёх лет. Можешь приспособить к своим каким-то изобретениям и использовать уже юниты, а не закроненные bash скрипты. А шары монтировать через <strong>sshfs</strong>, а не через вонючий, разваливающийся gluster. Фак еее! <a href = "video_files/sticker (25).webm">🐄</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-24">

      <div class="body details">
28 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message42">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.07.2023 12:05:36 +07">
12:05
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Доброе утро<strong>, </strong>наливай кофея и погнали. Щас<strong> </strong>расскажу<strong>, как мы сэкономили кучу денег на тестовой инфраструктуре. <br><br></strong>У меня есть 5 тестовых стендов. Каждый стенд это копия продакшена, но с открученными ресурсами и обезличенной базой данных.<br><br>Для каждого тестировщика свой отдельный стенд. Чтобы QA между собой не <s>попиздились</s> дрались и не ныли. Каждый стенд включает в себя 5 инстансов: <strong>балансировщик</strong>, <strong>база</strong>, <strong>фронтэнд</strong>, <strong>бекэнд</strong>, <strong>микросервисы</strong>. Считаем 5x5=25 серверов. Чето <s>дохуя</s> много. <a href = "video_files/sticker (26).webm">😐</a><br><br>Все сервера развернуты в Selectel. По итогу в месяц <strong>набегает приличная сумма</strong>. По бюджету прям заметно кусается.<br><br><strong>Думали мы, думали и придумали.<br><br></strong>Будем автоматически отключать всю эту ферму на ночь, в выходные и праздники. Но столкнулись с проблемой, что даже выключенные машины — тарифицируются как включенные. Сука. Ладно.... В Selectel так нельзя, а где можно? А можно в Yandex Cloud!<br><br>Перетащили полностью тестовую ферму в YC. Накидали бота для slack/mattermost, который будет управлять кнопками включения/выключения. И реализовали такой концепт:<br><br><strong>Концепт:<br><br></strong>1. Бот взаимодействует с API Yandex Cloud.<br>2. С <strong>18:00-08:00</strong> реализовано автоматическое отключение фермы.<br>3. Автоматически <strong>отключаем</strong> ферму в <strong>выходные</strong> и <strong>праздничные дни</strong> (бот взаимодействует с производственным календарем).<br>4. Если тестировщик желает поработать вне рабочее время, он пишет боту команду и бот включает ему нужные сервера.<br>5. Если тестировщик забыл выключить сервер, бот проверит, что нет активности (берет метрики с prometheus) и всё погасит.<br><br>Есть еще всякие нюансы, но это основной алгоритм. Да. В YC тарифицируются HDD/IP/четотамеще даже если всё погасить, но это копейки.<br><br><strong>По итогу</strong> если мы раньше платили 500к рублей в месяц только за тестовую инфраструктуру. Сейчас все это дело обходится в 100к, а порой и еще меньше. К примеру если тестировщик ушел в отпуск, то его сервер 2-3-4 недели будет выключен, а мы накопили себе на пивко.<br><br>Жалоб со стороны QA отдела не наблюдаем, значит решение рабочее. А сэкономленный бюджет можно смело пустить в дело: пропить либо выписать квартальные премии.<br><br><em>Сегодня закину еще один пост про костыли, правда после нативной интеграции, чото там про ЦОД и сети, от партнера залетит</em>, <em>не обессудьте</em>. <em>Ловите мясного пацана</em> <a href = "video_files/sticker (27).webm">👍</a> <br><br>Спасибо коллеги за внимание, увидимся чуть попозже!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message44">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.07.2023 15:06:24 +07">
15:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Про костыли</strong>. Ну а как ты хотел? У нас тут про такое будет ой как много. Это в идеальном мире есть кодстайл, кубернейтс с аптаймом 100500%, кодревью, юнит-тесты и т.п. А в реальном мире дела обстоят иначе.<br><br><strong>Короче, кейс. </strong>Есть у меня клиент, у клиента есть <strong>RabbitMQ</strong>.<br><br><em>RabbitMQ — программный брокер сообщений на основе стандарта AMQP — тиражируемое связующее программное обеспечение, ориентированное на обработку сообщений.<br><br></em><strong>Если уже совсем простыми словами</strong> — это аналог почтового ящика, люди туда скидывают письма, утром приходит почтальон, забирает письма и доставляет адресатам.<br><br>В <strong>RabbitMQ</strong> есть очередь, в очередь попадают транзакционные письма, которые неспешно нужно отправить пользователям. Очередь обрабатывается микросервисом, который написан в 90е года на каком-то форке perl’а, дада именно так! Тот кто его писал, давным-давно нянчит внуков, либо кормит рыб <a href = "video_files/sticker (28).webm">📺</a><br><br>В какой-то момент этот микро-<span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">сервис</span></span>-динозавр начинает троить и просто зависает при работе по протоколу <strong>amqp</strong>. Хотя визуально с ним все в порядке, в логах ошибок нет, собственно как нет и самих логов. Просто он в какой-то момент перестает выгребать очередь и на этом всё!<br><br>Поддерживать этот микросервис никто не хочет, но скорее всего просто не может. Переписывать тоже нет времени, нужно решение здесь и сейчас, как говорят блогеры — решение в моменте. <s>Ебанутая</s> Плохая фраза, да!<br><br>Ну раз клиент просит быстро решить проблему и согласен на костыли, да пожалуйста! Пишем ему <strong>bash&apos;ник</strong>, забираем 50к рублей и идем пить чай/кофе/смузи/пиво.<br><br><pre>#!/bin/bash<br><br>COUNT_Q=$(ssh user@bashdayz-d1 rabbitmqctl list_queues | grep &apos;email.send.mass&apos;|awk &apos;{print $2}&apos;)<br><br>if [ $COUNT_Q -gt 500 ]<br>then<br>    su - amqp-daemon -c &quot;cd ~/daemon &amp;&amp; daemon.pl stop&quot;<br>    su - amqp-daemon -c &quot;cd ~/daemon &amp;&amp; daemon.pl start&quot;<br>fi<br><br></pre><strong>Разбор скрипта:<br><br></strong>Скрипт работает в кроне на сервере рядом с микросервисом. Запускается каждые полчаса. После запуска, он подключается по ssh к серверу с очередями <strong>RabbitMQ</strong>. Проверяет общее количество писем в очереди <strong>email.send.mass</strong>. Если писем скопилось более 500, то значит ПРИПЛЫЛИ!<br><br>Оператор <code>-gt</code> в bash означает: <strong>Больше<br></strong>А конструкция <strong>su - amqp-daemon -c</strong> означает, что запускаем команды от пользователя <strong>amqp-daemon<br><br></strong>Ну а далее срабатывает логика перезапуска микросервиса, <strong>остановка</strong> и <strong>запуск</strong>.<br><strong>Профит</strong>. Клиент доволен как слон, а мы при деньгах. <a href = "video_files/sticker (29).webm">💰</a><br><br><em>Не забывыем прописать ssh public ключи, чтобы скрипт мог ходить на другие сервера без пароля. Ну про это ты должен знать. Если не знаешь, то обязательно погугли как работают ssh ключи</em>, <em>это база.<br><br></em>Также можно сюда прикрутить логирование, оповещения, экспортер в <strong>prometheus</strong> и на графиках в <strong>grafana</strong> все красиво вывести. Когда чо упало, когда перезапустилось, пустая ли очередь и т.п.<br><br>Переработав этот скрипт под свои нужды, можно получать вообще любые данные с любых серверов, не используя экспортеры. Ну и в дальнейшем строить логику в скрипте на этих данных. А самое главное это быстро реализуемо. <strong>Костыльно? Конечно!</strong> Но клиент всегда прав, а богатый клиент прав в двойне. Рабочие будни <a href = "video_files/sticker (30).webm">😎</a><br><br><strong>С пятницей ребят! Всем хороших предстоящих выходных и самое главное — берегите себя.<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-25">

      <div class="body details">
30 July 2023
      </div>

     </div>

     <div class="message default clearfix" id="message45">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.07.2023 14:06:30 +07">
14:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_6@30-07-2023_14-06-30.jpg">

         <img class="photo" src="photos/photo_6@30-07-2023_14-06-30_thumb.jpg" style="width: 194px; height: 260px"/>

        </a>

       </div>

       <div class="text">
Утречка всем! Не думал, что буду в выходные пилить посты, но чо поделаешь, работа есть работа. <strong>Пользуешься VIM?</strong> Тогда лови крутую разработку от очередного упоротого гика. <br><br>Если педаль нажата, редактор находится в режиме вставки текста. При отпускании, переходит в обычный режим. Автор проекта планировал добавить еще пару педалей для более продуктивной работы. Но чет не фартануло. А я бы еще руль <a href = "video_files/sticker (31).webm">😭</a> для перемещения по тексту прикрутил и коробку передач для повышения KPI. <br><br>Чем бы дитя ни тешилось. И это не шутка, это реальность. Посмотреть можешь на <a href="https://github.com/alevchuk/vim-clutch">гитхабе</a>. Проект как я понял давно не развивается, но возможно ты подхватишь идею и приладишь к vim свой гитарный свитчер на 5 кнопок.<br><br><em>После интеграции от партнера, залетит еще один интересный и необычный пост, ожидайте...<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message47">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.07.2023 16:41:18 +07">
16:41
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Еще раз привет всем отдыхающим! Грузить не буду, всё по делу и быстренько, приключений на 5 минут. Иначе никак <a href = "video_files/sticker (32).webm">🚑</a><br><br>Решил я упороться и упоролся. Захотелось мне короче прям из консоли вызывать всплывающую подсказку по хоткею. <strong>Нажал хоткей</strong> появилась справка-шпаргалка, <strong>отпустил</strong> и она закрылась.<br><br><strong>ДА! Прям из консоли! </strong>Так как иксов на серверах нет, нужно было идти другим путем, а путь оказался ну совсем неочевидный. Я до сих пор не понимаю, почему такая больная мысль меня посетила, видимо задачи в бэклоге закончились и стало скучно.<br><br>Проштудировав документацию по <strong>readline</strong>, я <s>нихуя не понял</s> ничего не нашел, видимо там нет нужных механизмов позволяющих определять нажата ли клавиша или отпущена.<br><br><em>Readline — библиотека GNU Project, которую Bash и другие программы с CLI-интерфейсом используют для взаимодействия с командной строкой.<br><br></em>Но нет ничего невозможного, раз <strong>readline</strong> шлет меня в жопу, повесим <strong>read</strong> на стандартный ввод. Когда клавиша будет отпущена, <strong>read</strong> вернет ошибку и выполнение скрипта перейдет к следующей инструкции, ну и по итогу скрипт завершится.<br><br><em>Если кто-то тебе говорит — это сделать невозможно! Он либо пиздит врет либо просто не хочет этим заниматься. Всё можно сделать, было бы желание!<br><br></em>Ничего не понял? Забей, это мысли в слух, главное реализация, а не скучная теория. В общем пишем скрипт и кидаем его в <code>/usr/local/sbin/cheat_shit.sh </code>чмодим <code>chmod +x cheat_shit.sh</code> чтобы он в экзешник превратился.<br><br><pre>#!/bin/bash<br><br>tput civis                          <br>tput smcup                          <br>tput cup 0 0           <br><br>trap &apos;tput rmcup;tput cvvis&apos; EXIT    <br><br>echo &apos;Hello,this is Cheat-Shit&apos;<br>echo &apos;------------------------&apos;<br>echo &apos;а тут можешь написать всё, что захочешь&apos;<br>echo &apos;------------------------&apos;<br>echo &apos;source: https://t.me/bashdays&apos;<br><br>read -srn1 -t 0.7<br><br>while read -srn1 -t 0.1 <br>do<br>:<br>done<br>exit <br><br></pre><strong>ОЧЕНЬ СТРАШНО! </strong>Держу пари мало кто про такое вообще слышал и тем более видел. Но такое в <strong>bash</strong> вполне реализуемо и <strong>в школе такому не научат</strong>. <br><br><strong>Кратенько:<br><br></strong><code>tput civis</code> = скрываем курсор<br><code>tput smcup</code> = переходим на альтернативный экран<br><code>tput cup 0 0</code> = переводим курсор в начало строки<br><code>trap &apos;tput…&apos;</code> = после выхода зачищаем весь мусор<br><br>Далее прописываем бинд в <code>~/.bashrc</code> и вешаем вызов скрипта на <strong>CTRL+h<br><br></strong><pre>bind -x &apos;&quot;\C-h&quot;:&quot;/usr/local/sbin/cheat_shit.sh&quot;&apos;<br><br></pre>Перезапускаем сессию. Теперь при нажатии <strong>CTRL+h</strong> у меня поверх рабочей консоли открывается попап с нужным мне текстом. В тексте может быть шпаргалка либо котик <a href = "video_files/sticker (33).webm">😑</a> либо что-то еще полезное.<br><br>Как повторить для zsh, ХЗ, я не разбирался. Если будут наработки, скидывайте в <a href="https://t.me/bashfeedbot">бота</a>, сделаю отдельный пост.<br><br>Ну и для гиков, кто хочет покопаться поглубже, можешь зама́нить и захелпить:<br><br><pre>man 3 readline<br>man bash (раздел readline)<br>man tput<br>man stty<br>help trap<br>help read<br>help bind<br>man 5 terminfo<br><br></pre>Помимо шпаргалки по хоткею, ты можешь запустить вообще любой скрипт. Тут уже зависит от полета фантазии. Больше не смею тебя отвлекать, спасибо за внимание. Давай пять и погнали дальше отдыхать!<br><br><a href = "stickers/AnimatedSticker (2).tgs">✅</a><a href="https://telegra.ph/Bash-Pop-up-07-30"> ВИДЕО КАК ЭТО РАБОТАЕТ<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-26">

      <div class="body details">
1 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message48">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.08.2023 14:06:28 +07">
14:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вот и август на носу, еще совсем чуть-чуть и снова новый год. Как говорится — дорогу осилит идущий. Так что не останавливаемся и продолжаем изучать новое.<br><br>Сегодня покажу вкусный трюк, <strong>как узнать физическое расположение файла на диске</strong>. Нет, не его путь, а именно в какой области жесткого диска этот файл находится. Поехали. <a href = "video_files/sticker (34).webm">🏃‍♂️</a><br><br><strong>Создаём подопытный файл:<br><br></strong><pre>printf &apos;%s\n&apos; {a..d} &gt; /tmp/test.txt<br><br></pre>либо так:<br><br><pre>echo {a..d} &gt; /tmp/test.txt<br><br></pre>После создания файла, нужно запустить команду <strong>sync</strong>, но можно и не запускать, спустя несколько секунд linux сам всё нужное сделает. Я запускаю, потому что мне важна чистота эксперимента.<br><br><em>sync — утилита Unix, предназначенная для обновления файловых систем и для синхронизации данных на диске с данными в памяти. При этом выполняется системный вызов sync, который вызывает запись всех буферизованных изменений метаданных файлов и данных в базовые файловые системы. Он гарантирует, что все, что хранилось в памяти, будет записано на диск, предотвращая потерю данных, хранящихся в кеше, при аварийном завершении работы.<br><br></em>Так, файл успешно создан, давай посмотрим что внутри:<br><br><pre>cat /tmp/test.txt<br><br>abcd<br><br></pre>Ок. Теперь давай <strong>узнаем физическое расположение файла на диске</strong>, для этого запускай команду:<br><br><pre>filefrag -b512 -v /tmp/test.txt<br><br></pre><em>Программа filefrag (из пакета e2fsprogs) показывает насколько сильно фрагментирован файл.<br><br></em>После выполнения команды, смотрим результат. Нам важна колонка:  <strong>physical_offset</strong> в моём случае я получил такие значения:<br><br><pre>4612136..4612143<br><br></pre>Отлично. Теперь я знаю точное расположение файла на жестком диске. <strong>А давай прочитаем его прям с диска!</strong> Для этого стартуем:<br><br><pre>sudo dd if=/dev/sda1 skip=4612136 status=none count=8<br><br></pre>Важно правильно указать свой диск <strong>/dev/sdX</strong>. Ну и в параметр <strong>skip</strong> подставить первое значение из колонки <strong>physical_offset<br><br></strong>По итогу запуска, я получаю ту же картину. Только без применения сторонних утилит вроде <strong>cat</strong> и т.п..<br><br><pre>abcd<br><br></pre><strong>Ну и вишенка. </strong>Если я удалю файл <code>rm /tmp/test.txt</code> и затем выполню предыдущую команду:<br><br><pre>sudo dd if=/dev/sda1 skip=4612136 status=none count=8<br><br></pre>То получу тот же вывод <strong>«abcd»</strong>, потому что файл на диске продолжает лежать и занимать место. Это визуально он исчез, чтобы тебе глаза не мозолить. Но зная его <strong>physical_offset</strong> вполне можно до него дотянутся и восстановить при желании.<br><br><strong>Полезно? Полезно!</strong> Для чего это можно применить? Нууу не знаю, коллега к примеру таким образом восстанавливал базу данных, которую в пятницу вечером решили случайно удалить. А бэкапы съели мыши.<a href = "stickers/AnimatedSticker (3).tgs">🐁</a> Кстати успешно восстановил. Ну это уже лирика…<br><br>Очередную порцию полезных знаний я тебе выдал, ставь лайк, изучай. Увидимся! <a href = "video_files/sticker (35).webm">😻</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-27">

      <div class="body details">
3 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message49">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="03.08.2023 19:50:06 +07">
19:50
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Мой каррент муд на сегодня «голова два уха». Но оставить тебя без новых знаний, я не в праве. Так что <strong>сегодня будем прикручивать новогоднюю гирлянду к логам</strong>. Летс мазафака го! <a href = "video_files/sticker (36).webm">🕺</a><br><br>У меня в арсенале имеется ELK, но его в основном используют наши разработчики, которые привыкли мышкой натыкивать простые запросы. А я угораю по олдскулу, захожу на нужный мне сервер и тейлю/грепаю логи прям в консоли. <br><br>Какие-то особые инциденты конечно же разгребаю в ELK, но это бывает очень редко.<br><br><em>ELK – это аббревиатура, используемая для описания стека из трех популярных проектов: Elasticsearch, Logstash и Kibana. Стек ELK, зачастую именуемый Elasticsearch, предоставляет возможность собирать журналы всех ваших систем и приложений, анализировать их и создавать визуализации, чтобы мониторить приложения и инфраструктуры, быстрее устранять неполадки, анализировать систему безопасности и многое другое.<br><br></em><strong>Минус консольных логов</strong> — все серо и бездушно, все сливается в одну портянку, приходится порой тушить жопу и закапывать глазики «артелаком». <a href = "video_files/sticker (37).webm">📺</a><br><br>Но это решаемо. <strong>Есть прекрасная утилита</strong> под названием <strong>ccze</strong>. Это незаменимый помощник, который <strong>раскрасит твои логи</strong> в цвета новогодней елки. И самое главное <strong>выделит красным цветом все ошибки</strong>.<br><br>В стандартные пакеты linux эта утилита не входит, так что тут нужно ее установить командой: <code>apt/yum install ccze<br><br></code><strong>Ну а после установки, применяем на практике:<br><br></strong><pre>cat /var/log/syslog | ccze -A<br><br></pre>Ключ <code>-A</code> = Generate raw ANSI output<br><br>Вместо <strong>cat</strong> можно иcпользовать и <strong>tail</strong>, чтобы логи бежали в реальном времени. Я к примеру при дебаге использую исключительно <strong>tail</strong>.<br><br><pre>tail -f /var/log/syslog | ccze<br><br></pre><em>tail позволяет выводить новые строки в интерактивном режиме, либо выводить заданное количество строк с конца файла.<br><br></em><strong>Ура, теперь у нас настоящая новогодняя ёлка!</strong> От серых будней ничего не осталось, все чётенько, по цветам, ошибки промаркированы. Пушка!<br><br>А <strong>самая приятная киллер-фича</strong> этой утилиты, это то, что я могу записать логи в html файл. А затем передать этот файл разработчикам, которые частенько приходят с просьбой — Олег, выгрузи нам пожалуйста последние 500 строк.<br><br><pre>tail -n 500 /var/log/auth.log | ccze -h &gt; ~/log.html<br><br></pre>Раз и готов html файл, который можно открыть в браузере и посмотреть как иностранные бедолаги с дикого запада пытались подобрать пароль на 22 порт. <strong>И всё это будет в цвете!<br><br></strong>У утилиты <strong>ccze</strong> есть много других ключей, а также присутствует поддержка плагинов. Но я пользуюсь функционалом из коробки. Список доступных плагинов можно глянуть командой: <br><br><pre>ccze -l<br><br></pre>Ну а если есть желание что-то там перепилить по цветам и т.п. всё это можно сделать в конфигурационном файле: <code>/etc/cczerc<br><br></code><strong>Короче бери на вооружение, утилита мастхев.</strong> Картинка к посту опять не влезла, заливаю на телеграф, чтобы ты смог посмотреть на эту новогоднюю гирлянду и решить, что она тебе тоже ой как необходима.<br><br><a href = "stickers/AnimatedSticker (2).tgs">✅</a> <a href="https://telegra.ph/Novogodnyaya-yolka-08-03">Картинка с ccze<br><br></a>В следующем посте расскажу как быстро передавать разработчикам подобные файлы, не мучаясь со скачиванием их на локальную машину, а затем приседать с пересылкой через слак/маттермост.<br><br><strong>Давай краба, подписывайся, тыкай палец вверх, увидимся!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-28">

      <div class="body details">
6 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message51">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.08.2023 14:35:58 +07">
14:35
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Пятница и «Международный день пива» прям подкосили. Спасибо, но в следующем году я на этот фестиваль не куплюсь <a href = "video_files/sticker (38).webm">❤️</a><br><br>Сегодня пусть и выходной, но это ничего не меняет. Поведаю про фичу с помощью которой можно <strong>легко передавать разработчикам нужные им файлы с серверов</strong>.<br><br>Частенько меня просят скинуть какой-нибудь огрызок лога, выгрузку и т.п. Тут <strong>алгоритм простой</strong>:<br><br>- зашел на сервер по ssh<br>- нашел/сделал то, что нужно передать<br>- если файл большой, то сжать<br>- вспомнить синтаксис <strong>scp<br></strong>- на локальной машине натыкать команду чтобы забрать себе этот файл<br><br><code>scp -r user@bashdayz:/tmp/nginx.log /home/user/tmp/</code> <br><br>- скинуть файл человеку в слак/маттермост<br>- если файл большой, выложить его на корпоративный <strong>google drive<br></strong>- скинуть человеку ссылку на файл на корпоративном диске<br><br><em>scp (Secure CoPy) — утилита для безопасного копирования данных между Linux-системами по протоколу SSH<br><br></em><strong>Тут подходит фраза из мема:</strong> вот это <s>нихуя</s> ничего себе! <a href = "video_files/sticker (39).webm">😳</a> Ладно если это делаешь раз в месяц. Но если такое происходит пару раз в неделю, то ощущаются первые нотки выгорания.<br><br>Все гениальные вещи придумали ленивые люди. А мы с тобой одни из них. Поэтому бо́льшую часть я успешно автоматизировал через <strong>bash</strong>.<br><br>А вот и сам скрипт. Обзови его <strong>trans</strong> и закинь в <strong>/usr/local/sbin</strong>. Ну и не забывай про <code>chmod +x /usr/local/sbin/trans</code>.<br><br>Запускается всё это безобразие так: <strong>trans &lt;файл&gt;<br><br></strong><pre>#!/bin/bash<br><br>SIZE=1000000<br><br>if [ -n &quot;$(find &quot;$1&quot; -prune -size +&quot;$SIZE&quot;c)&quot; ]; then<br>    tar -czvf /tmp/$1.tar.gz $1<br>    curl --upload-file /tmp/$1.tar.gz https://transfer.sh/$1.tar.gz<br>    rm /tmp/$1.tar.gz<br>else<br>    curl --upload-file $1 https://transfer.sh/$1<br>fi<br><br></pre><strong>Логика такая:<br><br></strong>1. Если размер файла &gt; 1 мб, то сжимаем<br>2. После сжатия загружаем файл в сервис <a href="https://transfer.sh/">transfer.sh<br></a>3. Подчищаем за собой<br>4. Если файл &lt; 1 мб, то просто загружаем как есть в тот же сервис <a href="https://transfer.sh/">transfer.sh<br></a>5. После загрузки <strong>в консоль выводится ссылка для скачивания<br></strong>6. Копируем полученную ссылку и передаем разработчику<br>7. Профит. Минимум действий, максимум удобства<br><br>Сервис <a href="https://transfer.sh/">transfer.sh</a> это очень удобная и простая штука, которая позволяет обмениваться файлами с помощью <strong>curl/wget</strong>. Без регистрации и смс. Лимиты приличные 10гигов на файл, 14 дней хранятся на сервере. Есть возможность зашифровать перед отправкой и проверить на вирусы. <strong>И все это бесплатно.<br><br></strong><em>А еще в curl можно передать заголовки -H &quot;Max-Downloads: 1&quot; -H &quot;Max-Days: 5&quot; и тогда файл разрешат скачать только один раз, а через пять дней он сам удалится. Пожалуй очень удобно.<br><br></em><strong>Тут конечно возникает вопрос — эммм, но это же не безопасно? </strong>Конечно не безопасно, поэтому годится лишь для передачи какой-то некритичной информации. А я передаю чисто логи, в них ничего критичного нет.<br><br>Ну а если хочется передать сканы документов или реквизиты банковских карт, то в мой скрипт ты можешь встроить <strong>gpg</strong> шифрование. Либо переделать сжатие на <strong>7z</strong> и зашифровать по максимуму. Но опять же не рекомендую, лучше передавай важные документы другим, более безопасным способом.<br><br><strong>Мысли в слух:</strong> Вот есть корпоративный google диск, хранишь ты там абсолютно всё, включая секреты компании. Безопасно? НЕТ! Гугол давно уже у тебя всё спёр и всё про всех знает. Так что можно булки расслабить и перестать параноить. Ладно, опять в лирику ударились.<br><br>Короче <strong>бери на заметку</strong>, дорабатывай, переделывай. Можешь добавить <strong>xclip/pbcopy</strong> чтобы ссылка автоматом в буфер обмена копировалась. Ну и зайди на сайт <a href="https://transfer.sh/">transfer.sh</a> и посмотри все возможности, которые они предоставляют. Там все с примерами, разберется любой.<br><br><em>А можно создать приватный телеграм/слак/маттермост канал, добавить туда разработчиков и в скрипте прикрепить отправку ссылки в этот канал. Тогда даже ссылку не нужно будет руками копировать и передавать разработчику, максимальная автоматизация.<br><br></em><strong>Удобно? Удобно!</strong> А главное максимально просто. Хорошо тебе провести остаток выходных, ну и увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-29">

      <div class="body details">
8 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message52">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.08.2023 13:31:46 +07">
13:31
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
И снова здравствуй. Разбирался я тут на досуге с доменной зоной <strong>.to</strong> Моей целью было <strong>получить значение Expires on</strong>. То есть дату, до которой нужно продлить домен.<br><br>Как мы обычно делаем? Запускаем команду <code>whois &lt;domain&gt;</code> и получаем желаемое. Но это не работает с доменной зоной <strong>.to</strong>. Если не веришь, можешь самостоятельно убедиться. Получишь массу информации, но никак не значение Expires on.<br><br><strong>Отправляемся на раскопки.<br><br></strong>Существует корневой whois сервер не для доменов, а для зон. Называется он <a href="whois.iana.org">whois.iana.org</a>. С помощью него можно получить данные по конкретной зоне, контакты, телефоны и т.п. <br><br><strong>Проверяю нужную мне зону .to<br><br></strong><pre>whois to -h whois.iana.org<br><br>whois:     whois.tonic.to<br>status:    ACTIVE<br>remarks:   Registration information: http://www.tonic.to/<br>created:   1995-12-18<br>changed:   2022-06-01<br>source:    IANA<br><br></pre>Отдается куча информации. И что мне с этим делать? <a href = "video_files/sticker (40).webm">😐</a><br><br>Ладно, я парень настырный. Пробую так:<br><br><pre>whois best.to -h whois.tonic.to<br><br></pre>Получаю тот же ответ что и раньше, ну нет нигде <strong>Expires on</strong>, шляпа какая-то.<br><br><strong>В ответе вижу строчку:</strong> <code>remarks: Registration information: http://www.tonic.to/<br><br></code>Ок. Раз ничего не получается, самое время идти читать документацию, может в ней будет что-то полезное.<br><br><strong>Натыкаюсь на такой пункт:</strong> <em>Предоставляет ли Tonic услугу whois? Компания Tonic не поддерживает базу данных whois, содержащую информацию о владельцах регистраций, поскольку многие наши клиенты считают, что публичное размещение такой информации нарушает их частную жизнь. Более того, мы никогда не будем продавать списки рассылки наших клиентов.<br><br></em><strong>Приехали.</strong> Но чуть ниже вижу: всю доступную информацию по домену, ты можешь попробовать получить по ссылке: <a href="https://www.tonic.to/whois?best.to">https://www.tonic.to/whois?best.to</a><br><br>А давай попробуем, вариантов у нас не много:<br><br><pre>curl https://www.tonic.to/whois?best.to<br><br>&lt;pre&gt;<br>Domain:               best.to<br>Created on:           Fri Apr 23 02:27:04 2021<br>Last edited on:       Sat May 27 06:48:58 2023<br>Expires on:           Sun Apr 28 07:33:28 2024<br>Primary host add:     None<br>Primary host name:    ns-494.awsdns-61.com<br>Secondary host add:   None<br>Secondary host name:  ns-1424.awsdns-50.org<br>END<br><br></pre>ОПА! <strong>Есть контакт</strong>, ‌Expires on как на ладони. Можно двигать таску в Done и писать экспортер для prometheus. И возможно однажды alertmanager вовремя сообщит, что стоило бы продлить домен, но это не точно <a href = "video_files/sticker (30).webm">😎</a><br><br><em>После плановой интеграции про тимлидов, закину тебе еще какое-нибудь интересное чтиво. На связи!<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message54">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.08.2023 16:18:46 +07">
16:18
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Пилил я как-то задачу связанную с мониторингом тестового сервера. С одной стороны ну что там сложного, воткнул везде <strong>node_exporter</strong> и вперед, пусть <strong>prometheus</strong> ходит и забирает с них метрики. Всё логично.<br><br><strong>Но есть закон подлости</strong>: если оценить задачу в 5 минут, то обязательно вылезут подводные камни. Собственно они и вылезли. Сейчас расскажу.<br><br><strong>Тестовый сервер представляет нечто подобное:<br><br></strong><pre>- балансировщик (белый айпишник)<br>   - фронтэнд (192.168.0.3)<br>   - бекэнд   (192.168.0.4)<br>   - база     (192.168.0.5)<br><br></pre>У <strong>[балансировщика]</strong> есть белый айпишник, у остальных (фронтэнд, бекэнд, база) только серые. Хм… ну и как <strong>prometheus</strong> будет ходить на серые инстансы и забирать метрики? Да никак! <a href = "stickers/sticker (20).webp">🤒</a><br><br>Уффф. Пошел смотреть в сторону <strong>pushgateway</strong>, чтобы инстансы сами метрики пушили в <strong>prometheus</strong> или сразу в <strong>VictoriaMetrics</strong>.<br><br><em>VictoriaMetrics — быстрая и масштабируемая СУБД для хранения и обработки данных в форме временного ряда (запись образует время и набор соответствующих этому времени значений, например, полученных через периодический опрос состояния датчиков или сбор метрик).<br><br></em>Но тут снова грабли. У <strong>prometheus</strong> тоже нет белого айпи. Это провал! Какой-то замкнутый круг получается. Забрать метрики не можем, отдать тоже не можем.<br><br>Выдавать белые айпишники ой как не хочется, по причине — лень настраивать фаерволы и прочую шляпу. Но что же делать? <strong>Правильно — достаём костыли! <br><br></strong>Так как у тестовых серверов на <strong>[балансировщике]</strong> есть белый ip адрес, будем привлекать <strong>iptables</strong> и жёстко роутить.<br><br><strong>На балансировщике с белым ip, выполняем:<br><br></strong><pre>-A PREROUTING -p tcp -m tcp --dport 1001 -j DNAT --to-destination 192.168.0.3:9100<br>-A PREROUTING -p tcp -m tcp --dport 1002 -j DNAT --to-destination 192.168.0.4:9100<br>-A PREROUTING -p tcp -m tcp --dport 1003 -j DNAT --to-destination 192.168.0.5:9100<br>-A POSTROUTING -j MASQUERADE<br><br></pre>Идея заключается в том, что с портов 1001-1003 (на балансировщике) мы попадаем на внутренние инстансы с серыми айпишниками и забираем свои метрики с портов 9100.<br><br>А в <strong>prometheus</strong> говорим, иди на внешний айпишник балансировщика с портами 1001-1003 и выгребай данные с серых инстансов.<br><br><strong>prometheus.yml<br></strong><pre>---<br>- targets:<br>  - balancer:1001<br>  labels:<br>    env: test<br>    role: frontend<br>- targets:<br>  - balancer:1002<br>  labels:<br>    env: test<br>    role: backend<br><br></pre>Красота! Кейс рабочий, костыли присутствуют, графики красивые, тестировщики довольные. Ну а что еще надо? <strong>Think different!</strong> <a href = "video_files/sticker (41).webm">🧠</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a> <a href="" onclick="return ShowHashtag(&quot;monitoring&quot;)">#monitoring</a><em> </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-30">

      <div class="body details">
10 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message55">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.08.2023 14:55:06 +07">
14:55
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Не думал что этот вопрос настолько актуален — <strong>почему перестают работать очевидные правила iptables на хостовой машине, если на сервере запущены какие-либо docker контейнеры?<br><br>Давай разбираться.<br><br></strong>Если коротко, то когда ты запускаешь <strong>docker</strong> контейнеры, то все начинает работать <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">через жопу</span></span> по правилам маршрутизации самого <strong>docker’а</strong>. И плевать он хотел что у тебя там на хостовой машине было ранее сконфигурировано в плане безопасности.<br><br><strong>Давай рассмотрим на примере как с этим можно побороться.<br><br>Вводные: </strong>На сервере крутится контейнер nginx, порты 80 и 443 смотрят в мир, то есть открыты для всех.<br><strong>Задача: </strong>Нужно, чтобы порты 80 и 443 были доступны только для определенных IP адресов.<br><br>Если бахнуть на хостовой машине так:<br><br><pre>-A INPUT -s xxx.xxx.xxx.xxx/32 -p tcp -m tcp --dport 80,443 -j ACCEPT<br>-A INPUT -j REJECT --reject-with icmp-host-prohibited<br>-A FORWARD -j REJECT --reject-with icmp-host-prohibited<br><br></pre>То порты 80 и 443 так же будут доступны всем желающим. Вот на эти грабли почти каждый и наступает.<br><br>А решение простое, правим немного свой <strong>docker-compose.yml</strong> и добавляем <strong>networks</strong>. В моем примере я добавил сеть bashdays.<br><br><pre>version: &apos;3.2&apos;<br><br>services:<br> nginx:<br> image: nginx:1.20.1<br> container_name: nginx<br> ports:<br> - &apos;80:80&apos;<br> - &apos;443:443&apos;<br> networks:<br> - bashdays<br><br>networks:<br> bashdays:<br> driver: bridge<br> driver_opts:<br> com.docker.network.enable_ipv6: &quot;false&quot;<br> com.docker.network.bridge.name: &quot;docker_bashdays&quot;<br><br></pre>Ну и теперь на хостовой машине можно уже что-то запрещать или разрешать с помощью iptables.<br><br><pre>/sbin/iptables -F DOCKER-USER<br>/sbin/iptables -I DOCKER-USER -i eth0 -o docker_bashdays -j DROP<br>/sbin/iptables -I DOCKER-USER -i eth0 -s &lt;EXTERNAL IP&gt; -j RETURN<br>/sbin/iptables -I DOCKER-USER -i eth0 -p tcp --dport 80 -s &lt;CLIENT IP&gt; -j RETURN<br>/sbin/iptables -I DOCKER-USER -i eth0 -p tcp --dport 443 -s &lt;CLIENT IP&gt; -j RETURN<br>/sbin/iptables -I DOCKER-USER -i eth0 -o docker_bashdays -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT<br><br></pre>Где <strong>&lt;EXTERNAL IP&gt;</strong> это айпишник сервера который доступен из мира. А <strong>&lt;CLIENT_IP&gt;</strong> собственно айпишник клиента, которому мы разрешим конектится к порту 80 и 443. Все! Теперь у нас и <strong>docker</strong> в шоколаде и хостовые правила <strong>iptables</strong> работают «наверное» правильно.<br><br><em>Не забывай правильно подставить свой интерфейс ethX/enoX, а то всякое бывает.<br><br></em><strong>Важное замечание. </strong>После перезапуска контейнеров, <strong>docker</strong> снова перетрет правила на хостовой машине. Поэтому весь этот процесс хорошо бы автоматизировать. Я сильно не заморачивался, просто закинул правила в <strong>bash</strong> скрипт, повесил на крон (каждую минуту), да и все. <a href = "video_files/sticker (42).webm">🧠</a> Закостылил так закостылил.<br><br>Сегодня чуть позже покажу более правильный скрипт, который будет следить за ребутом <strong>docker</strong>, но по сути те же яйца, только сбоку. Рад был всех вас видеть!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message57">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.08.2023 19:06:40 +07">
19:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
По сетям мы немного прошлись, <strong>давай побашим</strong>. Накидаем скрипт автоматизации к <a href="https://t.me/bashdays/55">предыдущему посту</a>. Чтобы проверялись <strong>iptables</strong> правила и если их перетер <strong>docker</strong>, то они бы восстанавливались.<br><br>Назовем скрипт <strong>check_iptables.sh</strong> и закинем его в <strong>/usr/local/sbin</strong>. Башник максимально упрощаю, оставляю лишь суть. Поняв суть, ты сможешь самостоятельно сообразить нужную тебе логику.<br><br><pre>#!/usr/bin/bash<br><br>ips=(&quot;1.1.1.1&quot; &quot;2.2.2.2&quot; &quot;3.3.3.3&quot;)<br>IT=`which iptables`<br><br>$IT -C DOCKER-USER -j RETURN 2&gt;&gt; /dev/null<br>if [[ $? -eq 0 ]]<br>then $IT -D DOCKER-USER -j RETURN<br>fi<br><br>$IT -C DOCKER-USER -i eth0 -j DROP 2&gt;&gt; /dev/null<br>if [[ $? -eq 1 ]]<br>then $IT -A DOCKER-USER -i eth0 -j DROP<br>fi<br><br>for ip in ${ips[@]}; do<br> $IT -C DOCKER-USER -s $ip/32 -i eth0 -j RETURN 2&gt;&gt; /dev/null<br> if [[ $? -eq 1 ]]<br> then $IT -I DOCKER-USER 1 -s $ip -i eth0 -j RETURN<br> fi<br>done<br>exit 0<br><br></pre>Тут всё максимально просто. Есть массив айпишников в переменной <strong>ips</strong>. А далее просто проверяются <strong>iptables</strong> правила на их наличие. Ключ <strong>-C</strong> как раз то самое, необходимое чтобы определить не перетерлось ли что-то. Ну а если перетерлось, то оно само восстановится.<br><br><em>--check -C chain = Check for the existence of a rule<br><br></em>Последний блок прокручивает массив айпишников в цикле. Это весьма гибко, если тебе захочется добавить новых allow ip в свой массив. Ну а дальше кидаешь на всё это дело <s>болт</s> крон и радуешься <a href = "video_files/sticker (43).webm">😮‍💨</a>  Славьте меня! Я великий!<br><br><em>Еще если не знаешь полный путь до какой либо утилиты. Можешь применить конструкцию IT=`which iptables`. Нужный путь к утилите подставится автоматически. Указывать полный путь до утилиты очень важно если вешаешь скрипт на cron.<br><br>Потому что, cron может и не понять что ты от него хочешь. И просто сказать — у меня все ок! Но на неделе ничего не отработает как нужно. Про логирование крона я писал </em><a href="https://t.me/bashdays/31">в этом посте</a><em>, можешь там поглядеть как дебажить эту штуку.<br><br></em><strong>Для неопытных: </strong>чтобы повесить скрипт на cron, нужно выполнить команду <strong>crontab -e</strong> и вставить туда нужное. В моем случае получилось такое:<br><br><pre>*/1 * * * * /usr/local/sbin/check_iptables.sh<br><br></pre>Когда ты запускаешь команду <strong>crontab -e</strong>, открывается файл <strong>/var/spool/cron/crontabs/root</strong>. Все таски хранятся в нем. Естественно если у тебя другой пользователь, то замени <strong>root</strong> на него.<br><br>Можно и руками отредактировать типа: <strong>vim /var/spool/cron/crontabs/root</strong> но тогда если ты допустишь ошибку в синтаксисе <strong>cron</strong>, то оно тебе про это не сообщит. А вот если через <strong>crontab -e</strong> накосячишь, то сообщит мол — ты чо ваще? дурной? Ну это так математика, чтобы ты понимал откуда что берется и почему.<br><br>Ну а если у тебя сложности с пониманием <strong>cron</strong> синтаксиса, есть <a href="https://crontab.guru/">прекрасный сервис</a>, там всё наглядно и для человеков, отвечаю! <a href = "video_files/sticker (44).webm">😮‍💨</a><br><br><strong>Полезного много я сегодня тебе принес.</strong> Переваривай потихоньку и забирай себе в копилочку. А я пойду дальше думать, чем же тебя еще удивить. Завтра кстати снова пятница, пора готовиться к выходным. Давай, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-31">

      <div class="body details">
13 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message58">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.08.2023 15:18:32 +07">
15:18
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Наконец-то за окошком +15, а то в жару совсем невозможно работать. Привет отдыхающим и дежурным. <strong>Сегодня поиграем.<br><br></strong>Изучить командную строку и стать экспертом, можно не только по скучной документации и индийским <a href = "stickers/sticker (21).webp">🤒</a> роликам в ютубе. Сейчас я расскажу тебе о <strong>трех прекрасных играх</strong>, с помощью которых ты максимально быстро качнешь свой консольный левел.<br><br>Игры само собой англоязычные, но в наше время переводчиков хватает, да и базовый уровень английского сейчас есть у каждого. С виду всё кажется унылым <s>гавном</s>, но на деле затягивает, даже если у тебя игровая импотенция<br><br><strong>Первая игра называется BashCrawl<br><br></strong>Клонируем себе репу и запускаем через <strong>cat</strong>:<br><br><pre>git clone git@gitlab.com:slackermedia/bashcrawl.git<br>cd bashcrawl/entrance<br>cat scroll<br><br></pre>Ищем сокровища, собираем артефакты, проходим квесты, сражаемся с пиэмами и техдирами. Игра само собой представляет текстовый linux тренажёр. Чем-то напоминает рогалик <a href="https://crawl.develz.org/">dungeon crawl</a>, кстати можешь в онлайне в неё побегать если совсем уж скучно.<br><br><strong>Вторая игра называется </strong><a href="https://web.mit.edu/mprat/Public/web/Terminus/Web/main.html">Terminus<br><br></a>Тут устанавливать ничего не нужно, все работает в браузере. Открывается консоль, а дальше следуешь подсказкам. <strong>Из приятных мелочей:</strong> есть визуальная составляющая. По мере прохождения квестов, картинки меняются. Намного круче чем предыдущая <strong>BashCrawl</strong>, по крайней мере мне было в ней уютнее.<br><br><strong>Третья игра</strong> <a href="https://github.com/gannonk08/clmystery">CL Mystery / Crimescence Mystery with Answers<br><br></a>На мой взгляд самая крутая и сбалансированная из всех вышеперечисленных. <br><br><strong>Если коротко, то:</strong> В Терминал-Сити произошло убийство, и полиции TCPD нужна ваша помощь.<br><br>Чтобы поиграть, нужно скопировать репу и запустить:<br><br><pre>git clone https://github.com/gannonk08/clmystery.git<br>cd clmystery<br>cat instructions<br><br></pre>Ну а далее следовать инструкциям на экране. Очень интересный сюжет с детективной составляющей. Рекомендую. Довольно качественная реализация, а самое главное — залипательно.<br><br><em>Автор игры при создании воодушевлялся такими фильмами:<br><br></em><pre>Достать ножи: Стеклянная луковица (2022)<br>Убийство в Восточном экспрессе (2017)<br>Поиск (2018)<br>Достать ножи (2017)<br>Улика (1985)<br>Исчезнувшая (2014)<br><br></pre>И не нужна нам никакая плойка и дорогущая видеокарта. Сарказм. Нужна! Но можно и в консоли прекрасно поиграть, получив массу удовольствия. А самое главное в процессе игры — ты прокачиваешь не только паттерны, алгоритмы и логику, но и в игровом режиме знакомишься с командной строкой. <br><br>Если знаешь еще какие-то подобные тренажеры, скидывай в <a href="https://t.me/bashfeedbot">бота</a>, выпустим отдельным постом. Всех благ и хорошо отдохнуть! На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-32">

      <div class="body details">
15 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message59">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="15.08.2023 15:02:02 +07">
15:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Я уверен что почти все из вас встречались с таким комментарием: выполни эту команду <code>sudo rm -rf /*</code> и твоя проблема решится.<br><br>Но мало кто знает, что <strong>эта команда называется «Патч Бармина».<br><br></strong><em>Патч Бармина — шутка, описывающая универсальное средство устранения любых неполадок в Unix-системах. Сам «патч» состоит из одной строки, которую следует набрать в консоли root.<br><br></em>Данная команда действительно устраняет любые неполадки вместе с самой Unix-системой. Поэтому <strong>будь аккуратен</strong> в своих экспериментах, запускать такое можно только на подопытных стендах ради науки. Надеюсь ты успел дочитать до этого абзаца <a href = "stickers/sticker (22).webp">🤒</a> и не побежал проверять на продакшене.<br><br><strong>Давай разберем как работает «Патч Бармина»<br><br></strong>По умолчанию утилита <strong>rm</strong> проверяет аргументы командной строки на соответствие корневой директории. Если в <strong>rm</strong> передан аргумент <strong>/</strong>, то выведется предупреждение. Но с помощью опции <code>--no-preserve-root</code> это предупреждение можно отключить.<br><br>В случае команды <code>rm -rf /*</code> аргументами будет <strong>содержимое корневой директории</strong>. Оболочка <strong>bash</strong> передаст команде <strong>rm</strong> список. Чтобы посмотреть, что будет в списке, выполни:<br><br><pre>printf &apos;%s\n&apos; /*<br><br></pre>Выведется список папок и файлов. Но корневой директории в этом списке не будет. Ну а дальше команда <strong>rm</strong> начет удалять всё до чего сможет дотянуться. Даже если её запустить под обычным пользователем, многие файлы будут удалены.<br><br>Достаточно чтобы процессу были доступны чтение/запись/исполнение (rwx) для директории в которой будут удаляться файлы. Ну и чтение/исполнение (r-x) на компоненты пути до этой директории.<br><br><em>Права на чтение не обязательны если известен полный путь и он задан в качестве аргумента.<br><br></em>К примеру этой командой <code>rm -ri /*</code> давай удалим содержимое домашней директории пользователя. Но перед каждым удалением будет задаваться вопрос (<strong>ключ -i</strong>).<br><br><pre>rm: спуститься в защищённый от записи каталог &apos;/boot&apos;?<br>rm: спуститься в защищённый от записи каталог &apos;/dev&apos;?<br>rm: спуститься в защищённый от записи каталог &apos;/etc&apos;?<br>rm: спуститься в защищённый от записи каталог &apos;/home&apos;? y<br>rm: спуститься в каталог &apos;/home/user&apos;? y<br>rm: удалить обычный файл &apos;/home/user/.bashrc?<br><br></pre>Если мне что-то не нужно удалять, я просто нажимаю <strong>Enter</strong>, а для положительного ответа набираю <strong>«y»</strong> и жму <strong>Enter</strong>.<br><br>Также имеется еще одна опция <code>--preserve-root</code>, без аргументов эта опция как раз и включает проверку которую отключает <code>--no-preserve-root</code>. При задании этой опции с аргументом <strong>all</strong> директории чьи родители находятся на другой файловой системе (то что было смонтировано) — пропускуются. Например домашняя папка пользователя находится на отдельном разделе.<br><br><pre>rm -ri --preserve-root=all /*<br><br></pre>вывод будет таким:<br><br><pre>rm: пропускается &apos;/dev&apos;, поскольку он находится на другом устройстве<br>rm: и действует --preserve-root=all<br>rm: пропускается &apos;/run&apos;, поскольку он находится на другом устройстве<br>rm: и действует --preserve-root=all<br>rm: пропускается &apos;/tmp&apos;, поскольку он находится на другом устройстве<br>rm: и действует --preserve-root=all<br><br></pre><strong>Какие выводы.</strong> Даже если не указывать <code>--no-preserve-root</code>, команда <strong>rm</strong> может знатно начудить. Всегда гугли/читай, прежде чем бездумно копировать и запускать. Ну и всегда пробегайся глазами по чужим bash скриптам, особенно если эти скрипты дернуты у какого нибудь Васи Нонейма.<br><br>На этой прекрасной ноте, жму тебе руку и желаю хорошего дня!<br> <br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-33">

      <div class="body details">
16 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message60">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.08.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. На <code>gnu.org</code> как-то пролетал improvement тикет, который звучит так: <strong>Эмоджи/Смайлики не поддерживаются в оболочке bash</strong> в качестве имен переменных.<br><br>А правда, почему? Что бы отвечать на подобные вопросы, сначала нужно задать другой вопрос — что бы что?<br><br><strong>А ответ на этот вопрос простой:</strong> Ни одна из оболочек не поддерживает такое. Потому что POSIX не требует от оболочки поддержки символов, отличных от «цифр, букв, символа подчеркивания из набора кодировки (ASCII)». И добавлять поддержку эмоджи/смайлов вообще не имеет никакого смысла.<br><br><em>POSIX — набор стандартов, описывающих интерфейсы между операционной системой и прикладной программой, библиотеку языка C и набор приложений и их интерфейсов.<br><br></em>Данные правила действуют для именования переменных. <strong>А вот имена функций не имеют подобных ограничений.</strong> Так что в функциях ты вправе использовать эмоджи и это даже будет работать. <br><br>Вот пример рабочей функции, которая выводит Hello World.<br><br><pre>#!/bin/bash<br><br>😀😀😀 () {<br> echo &quot;hello world&quot;<br>}<br>😀😀😀<br><br></pre>Можно прям веселые bash скрипты писать (добавлять какашки и баклажаны) и радовать своих коллег. <a href = "video_files/sticker (45).webm">💕</a> Пусть орут.<br><br>Пока на этом все, после интеграции от партнера, чего-нибудь еще интересное закину почитать, увидимся! <br><br><em>Ну а если скучно и хочется прокрастинации, камон в мои мемные айти каналы: </em><a href="https://t.me/+MJX6Bw5AaIYyMzQy">@devopsina</a><strong> и </strong><a href="https://t.me/+2hVaY2A6gOxkMGRi">@devopsgarden<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message62">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.08.2023 16:57:45 +07">
16:57
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Если тебе приходится ковырять и писать скрипты на <strong>bash</strong>, порой хочется иметь под рукой какой-нибудь линтер. Чтобы уж слишком в говнокод не скатываться.<br><br>И такой линтер есть, называется <strong>shellcheck</strong>. С помощью него можно производить статический анализ кода и повышать качество твоих замечательных скриптов. Написан этот линтер на <strong>Haskell</strong>.<br><br><em>Haskell — стандартизированный чистый функциональный язык программирования общего назначения. Является одним из самых распространённых языков программирования с поддержкой отложенных вычислений.<br><br></em>С помощью этого линтера ты сможешь искать ошибки в текстах скриптов и получать отчеты о проведенных проверках. Это позволяет повысить производительность работы и качество кода.<br><br><strong>Установка элементарная<br><br></strong><pre>apt/yum/brew install shellcheck<br><br></pre>А использование этого линтера, вообще максимально простое:<br><br><pre>shellcheck script.sh<br><br></pre>Вот и все. Если твой скрипт написан чисто и без косяков, то после запуска этой команды, ничего не произойдет. А вот если запустить его на скрипте из <a href="https://t.me/bashdays/60">этого</a> поста, то в ответ получим много нецензурной брани и полезные советы. С одной стороны использовать эмоджи нам дают, но линтер как бы намекает на наш IQ.<br><br><pre>^-- SC1036 (error): &apos;(&apos; is invalid here. Did you forget to escape it?<br>^-- SC1088 (error): Parsing stopped here. Invalid use of parentheses?<br><br>For more information:<br>  https://www.shellcheck.net/wiki/SC1036 -- &apos;(&apos; is invalid here. Did you forg...<br>  https://www.shellcheck.net/wiki/SC1088 -- Parsing stopped here. Invalid use...<br><br></pre>Что еще сказать, этот линтер можно прикрутить в <strong>vim</strong>. Достаточно установить из репозитория плагин <code>Plug &apos;neomake/neomake’</code>. А в VSCode так и называется <strong>shellcheck</strong>.<br><br>А если лень ставить и тыкать, можешь воспользоваться <a href="https://www.shellcheck.net/">онлайн версией</a>. Я пользуюсь консольной версией, из коробки, без всяких дополнительных ключей. Но ключи все же имеются, можешь запустить <code>--help</code> и поглядеть сам, но там особо ничего такого нет.<br><br><a href = "stickers/AnimatedSticker.tgs">🐱</a> <strong>Проект shellcheck на </strong><a href="https://github.com/koalaman/shellcheck">github<br><br></a>Ну и котиков лови: <a href = "video_files/sticker (46).webm">🤭</a>. <a href = "video_files/sticker (47).webm">👀</a>  <a href = "video_files/sticker (48).webm">😊</a> кудаж без них.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-34">

      <div class="body details">
17 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message63">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.08.2023 14:28:04 +07">
14:28
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем доброе утро! По мотивам <a href="https://t.me/bashdays/58">поста</a> про изучения bash через игры. Мне в бота накидали достаточно много всего. Всем большое и огромное спасибо ребята! <br><br>Больше всего раз упоминалась игрушка <strong>«Bandit»</strong> от <strong>Overthewire</strong>. Давай обсудим.<br><br><em>Сюжет такой: Ты подключаешься к удаленной машине и в изолированном пространстве ищешь ключ для подключения к следующей машине, используя рекомендации на сайте. В описании практически каждого уровня имеется список команд, которые тебе могут пригодиться.<br><br></em>Устанавливать ничего не надо, заходишь на <a href="https://overthewire.org/wargames/bandit/bandit0.html">сайт</a>, выбираешь <strong>Level 0</strong> и читаешь условия задачи. Затем подключаешься физически по <strong>ssh</strong> к серверу и начинаешь игру.<br><br><pre>ssh -p 2220 root@bandit.labs.overthewire.org<br><br></pre>Сделано всё достаточно реалистично, можно представить себя хакером или пентестером. Хотя если ты уже хакер или пентестер <a href = "stickers/sticker (23).webp">🤒</a> то представлять ничего не нужно.<br><br><strong>Плюсы игры:</strong> У тебя есть задачи, которые нужно решить с помощью консоли. Помимо этого отлично прокачивается логика и навыки дебага.<br><br><strong>В общем рекомендую поиграть</strong>. Ну а если уперся, можешь глянуть полное прохождение на <a href="https://habr.com/ru/articles/505906/">хабре</a>. Да и на ютубе этого добра навалом.<br><br>Помимо <strong>«Bandit»</strong> на <a href="https://overthewire.org/wargames/">сайте</a> имеется еще с десяток игр, покопайся, обязательно что-то зацепит.<br><br>Я в прошлой жизни обожал игру <strong>uplink</strong>, просто жил в ней. Помню даже отреверсил и патч сделал, чтобы накинуть на баланс денег и купить крутое виртуальное железо. <strong>Artmoney</strong> почему-то ее никак не хотела ломать, пришлось на ассемблере инжектор писать.<br><br><em>Uplink — компьютерная игра, симулирующая деятельность хакера. Дебютный проект, выпущенный британской независимой компанией Introversion Software в 2001 году<br><br></em>Сейчас игра доступна для покупки в <a href="https://store.steampowered.com/app/1510/Uplink/">стиме</a>, стоит копейки, но можно и пиратку легко найти на трекерах да на олдскульных форумах.<br><br><em>У Introversion еще есть несколько крутых игрух, например крутецкая стратегия darwinia. Тоже рекомендую погонять. Ну и defcon. Короче все их игры это шедевры.<br><br></em>Как-то так. <strong>Сегодня еще один пост закину</strong>, после очередной интеграции, там <strong>побашим</strong> уже и новое разберем, так что на связи. Не прощаюсь.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message65">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.08.2023 18:01:30 +07">
18:01
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Хеллоу! Попался мне вчера чей-то очередной <strong>bash</strong> скрипт, в котором были такие конструкции:<br><br><pre>echo &apos;--------------&apos; <br>printf &apos;%s\n&apos; &apos;--------------&apos;<br><br></pre>Так-то нормальная практика, но смотрится как-то уж очень не профессионально. У <strong>python</strong> и прочих языков такое можно реализовать примерно так:<br><br><pre>python3 -c &apos;print(&quot;-&quot; * 80)&apos;<br>perl -E &apos;say &quot;-&quot; x 80&apos;<br><br></pre>А что-же с <strong>bash</strong>? Из коробки такой функции увы нет. <strong>Включаем «режим изобретателя»</strong>. Поехали.<br><br><pre>repeat(){<br>    for i in {1..90}; do echo -n &quot;$1&quot;; done<br>}<br><br>repeat &apos;-&apos;<br><br></pre>Создаём функцию с циклом <strong>repeat</strong>, в которую передадим символ «<strong>-</strong>» для повторения 90 раз. Вот оно! Уже намного лучше.<br><br>Теперь если мне нужно вывести какие-то заголовки в «рамке», я делаю так:<br><br><pre>repeat &apos;-&apos;;.<br>echo -e &apos;\nHeader 1\t\tHeader 2\t\tHeader 3\t\t\t\tHeader 4&apos;;<br>repeat &apos;-&apos;;<br><br></pre>Уже не плохо. Символ <strong>\t</strong> означает = <strong>Табуляция</strong>. Ну а <strong>\n</strong> я думаю ты и так знаешь = <strong>Новая строка</strong>.<br><br>Гуд. Но функция все равно не универсальная, хочется большего. Давай теперь передадим в функцию <strong>repeat</strong> количество повторов. В предыдущем скрипте у меня зашит харкод на 90 символов. Вуаля:<br><br><pre>repeat() {<br>    range=$(seq $2)<br>    for i in $range; do echo -n &quot;$1&quot;; done<br>}<br><br>repeat &apos;-&apos; 20<br><br></pre>Передаем в функцию 2 параметра, <strong>первый</strong> = какой символ loop’ить, <strong>второй</strong> = сколько будет повторов. В примере выше, символ «<strong>-</strong>» выведется 20 раз.<br><br><em>Команда seq в этом скрипте выводит последовательность целых чисел с шагом, заданным пользователем. По-умолчанию, выводимые числа отделяются друг от друга символом перевода строки, однако, с помощью ключа -s может быть задан другой разделитель.<br><br></em><pre># seq 5<br>1<br>2<br>3<br>4<br>5<br><br># seq -s : 5<br>1:2:3:4:5<br><br></pre>С этим ок, разобрались. А что если воспользоваться <strong>printf</strong>? Давай попробуем.<br><br>С <strong>printf</strong> это реализуется намного проще, вот варианты:<br><br><pre>printf -- &apos;-%.0s&apos; 1 2 3 4 5<br>printf -- &apos;-%.0s&apos; {1..20}<br><br></pre><strong>Разборка этой магии<br><br></strong>Двойное тире означает «<strong>флаги командной строки</strong>». Поскольку мне нужно вывести «<strong>-</strong>», двойное тире указывает команде <strong>printf</strong> не пытаться анализировать то, что идет после параметров командной строки. <a href = "video_files/sticker (49).webm">😶</a> ЧО?<br><br><strong>Короче простым языком: </strong>если выводишь символ «<strong>-</strong>» через <strong>printf</strong>, то нужно двойное тире. Если выводишь к примеру символ «<strong>~</strong>» можно обойтись такой конструкцией:<br><br><pre>printf &apos;~%.0s&apos; {1..20}; printf &apos;\n&apos;<br><br></pre>Просто при выводе «<strong>-</strong>» <strong>printf</strong> думает что ты ему какой-то ключ хотел подсунуть и заорет: <code>printf: -%: invalid option</code>. В общем такая вот особенность. Ну либо всех обмануть и сделать так:<br><br><pre>printf &apos;%.0s-&apos; {1..80}<br><br></pre>Подобное можно реализовать с помощью внешних утилит таких как: <strong>awk/sed</strong> и т.п. Но <strong>чем больше ты усложняешь, тем тяжелее это дебажить</strong>. Это утверждение справедливо вообще для всего.<br><br><strong>на закуску:<br></strong><pre>seq -s_ 20|tr -d &apos;[:digit:]&apos;<br><br></pre>Надеюсь ты узнал что-то новое. Спасибо за внимание, <strong>ставь лайк, репости и приводи</strong> к нам своих коллег и друзей. Забашим!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-35">

      <div class="body details">
21 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message66">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.08.2023 14:54:04 +07">
14:54
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет друзья-товарищи. Сегодня разберем полезную утилиту, которая позволяет из консоли сгенерировать <strong>временный адрес электронной почты</strong>. Поехали.<br><br><strong>Для чего вообще нужен временный адрес электронной почты? </strong>Лично мне он нужен для регистрации в сервисах, которые предварительно требуют проверки прежде чем я начну с ними работу. Сначала хочу убедиться, что сервис мне подойдет и будет отвечать моим требованиям. А лишь потом регистрироваться в нем на корпоративную почту.<br><br>Ну или к примеру, хочешь ты в комментариях на форуме кого-то <s>засрать</s> пристыдить, или оставить гневный отзыв на флампе — нужна почта для регистрации. Тут как раз подходит вариант с временным ящиком, который спустя какое-то время бесследно исчезнет.<br><br>Ведь как часто бывает — зарегистрировался на свою личную почту, а потом понеслись вагончики <s>с письками</s> со спамом и ненужными рассылками. <br><br>Можно конечно завести под это дело отдельный почтовый ящик, либо использовать конструкцию <code>hello+service@bashdayz.ru</code> (<strong>подставлять символ «+»</strong>), но мне гораздо удобнее получить временный почтовый ящик консольной командой и принять на него письмо. <strong>Сейчас расскажу как такое реализовать.<br><br>Будем использовать готовый bash скрипт<br><br></strong><pre>wget -O /usr/local/sbin/tmpmail https://raw.githubusercontent.com/sdushantha/tmpmail/master/tmpmail<br><br>chmod +x /usr/local/sbin/tmpmail<br><br></pre>Выкачиваем, помещаем в папку <strong>/usr/local/sbin</strong> и даем файлу атрибут на исполнение.<br><br><strong>Обязательно</strong> пробегаемся глазами по скаченному файлу, чтобы в нем не было приколов типа <a href="https://t.me/bashdays/59">«Патча Бармина»<br><br></a>Ок, Запускаем<br><br><pre># tmpmail<br>Could not find the following dependencies: jq w3m xclip curl<br><br></pre>Хм, устанавливаем зависимости:<br><br><pre>apt/yum/brew install jq w3m xclip curl<br><br></pre>Ну и запускаем повторно:<br><br><pre># tmpmail<br>[ Inbox for qxsgxmmeuas@1secmail.com ]<br><br>No new mail<br><br></pre><strong>Ну вот и всё!</strong> Временный адрес электронной почты готов и все это без лишних манипуляций в браузере. Теперь можешь на него получать коды и ссылки.<br><br><em>ВАЖНО! Отправлять письма с таких ящиков ты не можешь, они работают только на приём.<br><br></em>У скрипта есть несколько ключей, давай посмотрим:<br><br><strong>Сгенерировать НОВЫЙ временный адрес<br><br></strong><pre># tmpmail -g<br># tmpmail -g [ADDRESS]<br><br></pre>Если указать <strong>[ADDRESS]</strong>, то временная почта будет с твоим индивидуальным префиксом. Ну а если не указывать, то будет рандом.<br><br><strong>Выводит список доступных доменов</strong>, на которые можно создать временную почту<br><br><pre># tmpmail -d<br># tmpmail -g bashdayz@kzccv.com<br><br></pre>В <strong>первой строке</strong> выводится список доступных доменов, во <strong>второй строке</strong> я собираю себе индивидуальную почту из префикса+домен.<br><br><strong>Из основного это всё.</strong> Ну а чтобы <strong>посмотреть список входящих писем</strong>. Просто запускаешь заново:<br><br><pre># tmpmail<br>[ Inbox for bashdayz@kzccv.com ]<br>- 347359684 kzccv.com@email.workflowy.com Signup code for Workflowy<br><br></pre><strong>Для того чтобы прочитать:<br><br></strong><pre># tmpmail 347359684<br><br></pre>То есть передаешь идентификатор письма, которое нужно открыть. Либо можешь воспользоваться ключом <strong>tmpmail -r</strong>, тогда сразу откроется самое последнее письмо.<br><br>Я использую такую конструкцию, открываю последнее письмо в текстовом режиме.<br><br><pre>tmpmail -t -r<br><br></pre>Ключ <strong>-t</strong> открывает письмо в raw (сыром) виде. Если этот ключ не указывать, то письмо будет рендериться как HTML. Мне проще сразу открыть последнее и получить текст.<br><br>Эту утилиту вполне реально интегрировать со своими <strong>bash</strong> скриптами и полностью автоматизировать какую-то рутину. Например, если ты QA, то можешь в автотесты легко это закинуть и проверять кейсы про авторизацию и регистрацию новых пользователей. Тут полёт фантазии безграничный. <br><br>Ну и алиасы никто не отменял, создай парочку с нужными тебя ключами и вообще всё будет в шоколаде.<br><br><a href = "stickers/AnimatedSticker.tgs">🐱</a>  <strong>Проект на </strong><a href="https://github.com/sdushantha/tmpmail">github<br><br></a>Также можешь воспользоваться <a href="https://www.1secmail.com/">онлайн версией</a> если не хочешь ничего устанавливать.<br><br>Забирай в коллекцию, рекомендую! <a href = "video_files/sticker (23).webm">🐾</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message68">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.08.2023 19:16:28 +07">
19:16
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_7@21-08-2023_19-16-28.jpg">

         <img class="photo" src="photos/photo_7@21-08-2023_19-16-28_thumb.jpg" style="width: 260px; height: 189px"/>

        </a>

       </div>

       <div class="text">
В дополнении к <a href="https://t.me/bashdays/66">предыдущему посту</a> про временный адрес электронной почты. Порекомендую тебе еще один сервис, который существует уже лет 100 и работает как надежные часы. Сам иногда им пользуюсь. Ну а когда работал автотестировщиком, то использовал его в автотестах постоянно.<br><br>Называется <a href="https://putsbox.com/">putsbox</a>, про него мало кто знает, он распространен больше в англоязычном сегменте.<br><br>Устанавливать ничего не надо, зашел на сайт, нажал -<strong> Create a PutsBox</strong> и получил временный почтовый ящик. Все максимально просто, как мы с тобой и любим.<br><br><strong>Из плюсов: <br></strong>1. Можешь создать одновременно много ящиков<br>2. Легкая интеграция с Selenium, Capybara и др.<br>3. Личный кабинет после регистрации (не обязательно)<br>4. Доступ к ящику по прямой ссылке (можно шарить)<br>5. В любой момент можно уничтожить временную почту<br><br>Входящее письмо открывается как <strong>text/html/json</strong>. За json прям отдельный респект, можно сразу на бекенде его обрабатывать в тех же автотестах. Вот небольшой <a href="http://www.pablocantero.com/blog/2015/08/05/test-emails-with-automated-testing-tools/">мануал</a> как приручить к тестам.<br><br>А еще у них есть очень крутой инструмент <a href="https://putsreq.com/">PutsReq</a> который позволяет дебажить HTTP-запросы и отдавать фейковые ответы.<br><br>Собственно на этом всё, Давай, хорошего понедельника!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-36">

      <div class="body details">
23 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message69">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.08.2023 15:11:29 +07">
15:11
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Хаа.. Привет! Сегодня <strong>будем извлекать расширение и имя файла</strong> на <strong>bash</strong>. Для чего? А почему бы и нет! На самом деле это нужно знать, это база. Я часто вижу как это делают люди с помощью какой-то зиготы <a href = "stickers/sticker (24).webp">🤒</a> (регулярки/awk/sed), ну боль же. Не надо ничего усложнять, есть вещи на порядок выше.<br><br>Что такое имя файла и расширение, объяснять не буду, как говорил мой техдир — <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">заебал,</span></span> если интересно, сходи погугли. <br><br><strong>Теперь по делу.</strong> Берем какой-нибудь подопытный файл, пусть будет: <strong>bashdays.gzip</strong> и накидываем скрипт.<br><br><pre>#!/bin/bash<br><br>FILE=&quot;bashdays.gzip&quot;<br><br>FIRST=&quot;${FILE%.*}&quot;<br>SECOND=&quot;${FILE##*.}&quot;<br><br>echo $FIRST<br>echo $SECOND<br><br></pre>В переменной <strong>FILE</strong> заносим имя файла <strong>bashdays</strong> с расширением <strong>gzip</strong>. Далее в переменной <strong>FIRST</strong> отсекаем расширение <strong>gzip</strong>, в переменной <strong>SECOND</strong> отсекаем имя <strong>bashdays</strong>. По итогу на экран выведется такая шляпа:<br><br><pre>bashdays<br>gzip<br><br></pre>Понял? Легкотня, без гигантских регулярок и гавнокода. <strong>Сейчас объясню подробнее</strong>, что происходит.<br><br>Символ <code>%.*</code> означает отсекание всего после точки.<br>Символ <code>##*.</code> ну а тут наоборот, отсекание всего до точки.<br><br>Если бы файл назывался <strong>bashdays,gzip</strong> (через запятую), то наш скрипт, нужно было бы немного адаптировать под эту запятую.<br><br><pre>FIRST=&quot;${FILE%,*}&quot;<br>SECOND=&quot;${FILE##*,}&quot;<br><br></pre>Проще уже не объяснишь. Если не дошло, сам потыкай на примерах и уже точно въедешь в тему, на практике само собой всё проще и понятнее.<br><br><strong>Это один из способов</strong> реализовать желаемое. <strong>Но есть и другой</strong>. Давай воспользуется командой <strong>basename</strong>.<br><br><em>Команда basename в Linux печатает последний компонент в пути к файлу. Это особенно полезно в скриптах bash, где вы хотите извлечь имя файла из длинного пути к файлу.<br><br></em>Если тебе заранее известно расширение файла, в нашем случае оно известно как <strong>gzip</strong>. То мы сможем отсечь расширение такими способами (они идентичны): <br><br><pre>basename /tmp/bashdays.gzip .gzip<br>basename -s .gzip /tmp/bashdays.gzip<br><br></pre>В обоих случаях на экран выведется: <code>bashdays<br><br></code>Ключ <strong>-s</strong> удаляет завершающее расширение файла, но можно и из коробки запускать, не указывая его.<br><br>Еще есть ключ <strong>-a</strong>, в который можно передать несколько путей и извлечь сразу пачку. Но я ни разу не видел, что бы такое использовали где-то, так что можно забить.<br><br>С <strong>basename</strong> вроде всё, <strong>дальше у нас по списку dirname</strong>.<br><br><em>Команда dirname в Linux печатает путь к файлу с удаленным последним компонентом. Это в основном дает вам путь к каталогу из пути к файлу.<br><br></em><pre>dirname /usr/local/sbin<br>dirname /tmp/bashdays.gzip<br>dirname /usr/bin/date<br><br></pre>Результат будет таким:<br><br><pre>/usr/local/<br>/tmp/<br>/usr/bin/<br><br></pre>Ну а чо, вообще шикарно! <strong>Ну и вишня для гиков, магия с переменной </strong><a href="" onclick="return ShowCashtag(&quot;IFS&quot;)">$IFS</a>.<br><br><em>Переменная IFS (внутренний разделитель полей) используется для указания определенного разделителя для разделения строк.<br><br></em><pre>_file=&quot;/tmp/bashdays.gzip&quot;<br><br>OLDIFS=&quot;$IFS&quot;<br>IFS=&apos;.&apos;<br>set -- $_file<br>IFS=&quot;$OLDIFS&quot;<br><br>printf &quot;File: %s\nExt: %s\n&quot; &quot;$1&quot; &quot;$2&quot;<br><br></pre><strong>Кратенько:</strong> Определяем имя файла, задаем переменную <strong>IFS</strong> для извлечения имени файла и расширения, указываем разделитель <strong>«.»</strong> (точка), выполняем <strong>set</strong> для разделения на позиционные параметры, ну и выводим все на экран с помощью <strong>printf</strong> (но можно и через <strong>echo</strong>).<br><br>Выхлоп скрипта будет таким:<br><br><pre>File: /tmp/bashdays<br>Ext: gzip<br><br></pre><em>Команда set — это встроенная команда оболочки, которая позволяет отображать или устанавливать переменные оболочки и среды.<br><br></em>Уффф.. Как-то много букв получилось, пардон. Основные моменты рассмотрели, надеюсь твой интерес я удовлетворил. <strong>Спасибо за внимание, ставь лайк</strong>. А вечером закину еще что-нибудь занимательное. Давай, на связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message71">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.08.2023 22:01:12 +07">
22:01
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
День сегодня какой-то сумасшедший, троить жестко начинаю, но раз обещал еще один пост, значит нужно сделать.<br><br><strong>Как проверить, определена ли переменная в bash скрипте?</strong> Давай разберемся.<br><br>К примеру мне нужно установить переменную <strong>CRAZYDAY</strong> и выполнить определенные действия в моём скрипте. Если переменная <strong>CRAZYDAY</strong> задана, то срабатывает первая логика, если нет, то другая.<br><br>Чтобы узнать определена ли переменная я могу передать параметр <strong>-z</strong> условному выражению<strong> if</strong>.<br><br><pre>if [ -z ${CRAZYDAY+x} ];<br>then<br>    echo &quot;LOGIC 1&quot;<br>else<br>    echo &quot;LOGIC 2&quot;<br>fi<br><br></pre>либо с помощью команды <strong>test<br><br></strong><pre>if test -z ${CRAZYDAY+y}<br>then<br>    echo &quot;LOGIC 1&quot;<br>else<br>    echo &quot;LOGIC 2&quot;<br>fi<br><br></pre><em>Команда test применяется для проверки условия. Она вычисляет выражение и, если его значение - истина, возвращает код завершения 0; иначе - ненулевое значение. Ненулевой код возвращается и в случае, когда выражение отсутствует. При проверке прав доступа используется действующий идентификатор пользователя.<br><br></em>Когда я запущу эти скрипты, не установив переменную <strong>CRAZYDAY</strong>, я получу результат <strong>LOGIC 1</strong>. Для того что бы получить <strong>LOGIC 2</strong>, я должен сделать:<br><br><pre>export CRAZYDAY=somestr<br>./script.sh<br><br></pre>Результатом будет <strong>LOGIC 2</strong>. Чтобы снова получить <strong>LOGIC 1</strong>, мне нужно сбросить установленную переменную с помощью команды: <code>unset CRAZYDAY</code>.<br><br><strong>Теперь давай разберем как работает:</strong> <code>${CRAZYDAY+x}<br><br></code>Выполняем последовательно команды и смотрим на выхлоп дебага:<br><br><pre>set -x<br>./script.sh<br><br></pre>вернуло:<br><br><pre>+ &apos;[&apos; -z &apos;]&apos;<br>+ echo LOGIC 1<br>LOGIC 1<br><br></pre>далее:<br><br><pre>CRAZYDAY=some ./script.sh<br><br></pre>появился параметр <strong>x</strong>, с ним и идет сравнение, x=some<br><br><pre>+ &apos;[&apos; -z x &apos;]&apos;<br>+ echo LOGIC 2<br>LOGIC 2<br><br></pre>далее:<br><br><pre>export CRAZYDAY=str<br>./script.sh<br><br></pre>вернуло то же самое<br><br><pre>+ &apos;[&apos; -z x &apos;]&apos;<br>+ echo LOGIC 2<br>LOGIC 2<br><br></pre>ну а теперь так:<br><br><pre>unset CRAZYDAY<br>./script.sh<br><br></pre>вернуло тоже самое как и в первом примере<br><br><pre>+ &apos;[&apos; -z &apos;]&apos;<br>+ echo LOGIC 1<br>LOGIC 1<br><br></pre>По сути <strong>x</strong> это расширение параметра <strong>bash</strong>, если переменная <strong>CRAZYDAY</strong> не задана, она не имеет в себе никакого значения. Ну а если задано, то все что внутри переменной <strong>CRAZYDAY</strong> заменяется просто на <strong>x</strong> и потом уже сравнивается в <strong>if</strong>.<br><br>Вместо <strong>x</strong> можно написать хоть что, будет работать. Но в бест практиках рекомендуют использовать именно <strong>x</strong> ну или <strong>y</strong>.<br><br>Есть и другие способы узнать задана ли переменная, но они более гиковские и совсем не человечные, поэтому опущу этот момент чтобы тебя не шокировать.<br><br><strong>set -x</strong> = включить режим дебага<br><strong>set +x</strong> = выключить режим дебага<br><br>Добавить пока больше нечего, изучай. Завтра снова увидимся, очередной CRAZYDAY. Ну и доброй ночи тебе!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-37">

      <div class="body details">
24 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message72">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="24.08.2023 20:14:27 +07">
20:14
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет друзья. Сегодня грузить дебагом и гиковскими вещами не буду, разберем простую, но важную тему: <strong>как проверить существует ли файл</strong>.<br><br>Сделать это можно несколькими способами:<br><br><pre>filename=&quot;test.txt&quot;<br><br>if [ -f $filename ];<br>then<br>    echo &quot;File exist&quot;<br>fi<br><br>if test -f $filename;<br>then<br>   echo &quot;File exist&quot;<br>fi<br><br></pre>В первом примере ключ <strong>-f</strong> означает = <strong>True if file exists and is a regular file</strong>. Возвращаем <strong>True</strong> если файл существует и является обычным файлом (не директорий, ни симлинком и т.п.)<br><br>Во втором примере я использую команду <strong>test</strong>. Оба этих примера делают одно и тоже, но в большинстве случаев обычно используется первый вариант.<br><br><em>Команда test предназначена для проверки типа файла и сравнения чисел и строк. Возвращает код возврата 0 (истина) или 1 (ложь) в зависимости от вычисления выражения. Выражения могут быть как унарными, так и бинарными.<br><br></em>Ну а если подставить символ <strong>«!»</strong> в условия, то сработает обратная логика:<br><br><pre>if [ ! -f $filename ];<br>if ! test -f $filename;<br><br></pre>Здесь мы уже получим сообщение — указанный файл не найден. Для разных задач, разные условия.<br><br><em>Да, часто возникают вопросы по ключу «-f», это не единственный ключ, их достаточно много, например можно проверить существование директории, сокета, установленные права и т.п. Табличку со всеми этими ключами я вынес отдельно </em><a href="https://telegra.ph/Kak-proverit-sushchestvuet-li-fajl-08-24">сюда</a><em>.<br><br></em>То же самое можно уместить в одну строчку, синтаксис будет таким:<br><br><pre>[ ! -f &quot;$filename&quot; ] &amp;&amp; echo &quot;file not found&quot; || echo &quot;file exist&quot;<br><br></pre>Подобные конструкции с одной стороны удобные, но ОЧЕНЬ плохо читаются, так что советую использовать их по минимуму. Например однострочник актуален в пайплайнах gitlab и т.п. где нужно умещать логику в одну строку.<br><br>Вещи с виду банальные, но важные, подобные конструкции очень часто используются в <strong>bash</strong> скриптах. В <a href="https://t.me/bashdays/41">этом посте</a> я использую проверку существования файла, для того чтобы определить подключен ли у меня сетевой диск. Опять же все зависит от задачи, которую ты хочешь решить.<br><br>Сегодня еще увидимся после интеграции, а вот завтра устроим разгрузочный день, пятница как-никак. Ладно давай пять, на связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-38">

      <div class="body details">
25 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message74">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="25.08.2023 00:12:22 +07">
00:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Давно не виделись <a href = "video_files/sticker (50).webm">🥳</a>  Давай сразу к делу. У меня есть скрипт с бесконечным циклом, который выполняет какие-то действия.<br><br><strong>Задача</strong>: нужно чтобы скрипт отработал 3 минуты и завершился.<br><br>Можно конечно запустить скрипт, подождать 3 минуты и руками его стопнуть через <strong>ctrl+c</strong>, но это не трувей. А что если нужно 5 минут или 45? Не буду же я сидеть всё это время в ожидании.<br><br>К счастью у нас с тобой есть утилита <strong>timeout</strong>, которая уже идет в коробке с Linux.<br><br><em>Timeout, это утилита командной строки, которая запускает указанную команду и завершает ее, если она все еще выполняется через определенный промежуток времени. Другими словами, timeout позволяет запустить команду с ограничением по времени. Команда timeout является частью пакета основных утилит GNU, который устанавливается практически в любом дистрибутиве Linux.<br><br></em>Вот с помощью этой утилиты, можно ограничивать по времени выполнение скриптов и команд. <strong>Давай рассмотрим примеры.<br><br></strong><pre>timeout 3s ping www.bashdayz.ru<br><br></pre>Команда <strong>ping</strong> отработает 3 секунды и завершится. Конечно у <strong>ping</strong> есть свои ключи для этого, но сегодня у нас про другое.<br><br>Синтаксис у команды <strong>timeout</strong> довольно простой:<br><br><pre>timeout DURATION COMMAND<br><br></pre><strong>DURATION</strong> = Длительность. Это число с плавающей запятой и с необязательным суфиксом следующего вида:<br><br><strong>s </strong>= секунды<br><strong>m</strong> = минуты<br><strong>h </strong>= часы<br><strong>d</strong> = дни<br><br><strong>COMMAND</strong> = сама команда или скрипт, которому нужно ограничить работу по времени.<br><br>Допустим мне нужно запустить какое-то приложение (например <strong>top</strong>) на удалённом сервере и через 3 минуты всё это безобразие прекратить. Ок, делаем такое:<br><br><pre>timeout 3m ssh user@bashdayz.ru -- /usr/bin/top<br><br></pre>Прошло 3 минуты, приложение гасится, <strong>ssh</strong> сессия завершается. Удобно? Удобно!<br><br><em>Если по истечению этого времени у тебя в терминале исчез курсор (частенько такое бывает), то выполни команду reset, терминал сбросится и всё вернется на круги своя.<br><br></em>Так же можно послать определенный сигнал завершения для приложения. К примеру:<br><br><pre>timeout -s 9 3m ping www.bashdayz.ru<br><br></pre>Чтобы получить список всех сигналов, можешь выполнить команду <strong>kill -l</strong> и посмотреть. Их там достаточно много. Я не заморачиваюсь и рублю с плеча сигналом <strong>9 (SIGKILL)</strong>. Убивать так убивать.<br><br>Вместо номера сигнала, можно указывать явное имя:<br><br><pre>timeout -s SIGTERM 5m ping www.bashdayz.ru<br><br></pre>У <strong>timeout</strong> есть еще несколько опций, но я никогда не видел, чтобы кто-то их использовал, так что можно забить. Возможно они пригодятся для каких-то специфичных задач, но я с такими к счастью не сталкивался.<br><br>Ладно. Утилита <strong>timeout</strong> это клева, а<strong> как реализовать то же самое не применяя ее, на чистом bash’е?</strong> Смотри:<br><br><pre>ping www.bashdayz.ru &amp; read -t 3 || kill $!<br><br></pre>В этом примере выполняется <strong>ping</strong> и по прошествию 3х секунд завершается. Тут уже тебе самому решать, использовать <strong>timeout</strong> либо подобную конструкцию.<br><br>А, точно, забыл объяснить про символ <strong>«$!»</strong>. Эта конструкция содержит в себе идентификатор процесса (<strong>PID</strong>) последнего выполненного фонового конвейера. В примере выше последним выполненным заданием был <strong>ping</strong>. То есть явно не нужно указывать <strong>PID</strong>, чтобы <strong>kill</strong> корректно отработал.<br><br>Собственно на этом всё. В Linux столько всего интересного, но не каждый про это интересное знает. Я изначально использовал <strong>bash</strong> конструкцию и только спустя какое-то время узнал про утилиту <strong>timeout</strong>. Век живи, век учись. <a href = "video_files/sticker (51).webm">😐</a> Котиков тебе и удачи. Давай, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-39">

      <div class="body details">
27 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message75">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.08.2023 20:10:31 +07">
20:10
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, коллеги. Ура, чтиво подвезли! Есть такая команда в Linux, называется <strong>cat</strong>. Ну ты наверняка про неё знаешь.<br><br>С помощью <strong>cat</strong> можно <strong>быстро посмотреть содержимое файла</strong>, объединить несколько файлов в один, ну и так далее.<br><br>Но сегодня речь пойдёт не о ней, <strong>существует более продвинутая утилита</strong>, которая делает то же самое, но по красоте и даже больше. И называется она <strong>batcat</strong>.<br><br><em>bat — это продвинутый клон cat с поддержкой подсветки синтаксиса и интеграцией Git.<br><br></em>Утилита <strong>bat</strong> поддерживает подсветку синтаксиса для огромного количества языков программирования. Выводит текст в читаемом виде и нумерацией строк. Сделано всё это <strong>для того, чтобы ты лучше воспринимал информацию</strong>, которая выводится на экран.<br><br>Также у нее отличная интеграция с <strong>git</strong>, ты всегда будешь видеть какие сроки были добавлены либо удалены. Вот это прям годнота, по крайней мере я использую ее на постоянке в своей работе. Это всяко лучше <strong>git status</strong> и т.п.<br><br>Утилита очень гибкая, можно кастомизировать как захочешь, менять темы, добавлять свои синтаксисы, наруливать пагинацию.<br><br><strong>Установка стандартная<br><br></strong><pre>apt/yum/brew install bat<br><br></pre>После установки создай alias либо симлинк, чтобы запускать ее тремя буквами <strong>bat</strong>, а не <strong>batcat</strong>, но можешь конечно и свой вариант с тремя буквами использовать.<br><br><pre>alias bat=&quot;batcat&quot;<br>mkdir -p ~/.local/bin<br>ln -s /usr/bin/batcat ~/.local/bin/bat<br><br></pre><strong>Как пользоваться? Элементарно:<br><br></strong><pre>bat ~/bashdays.sh<br><br></pre>Если нужно вывести на экран несколько файлов, то пишешь их подряд через символ пробела.<br><br>Если нужно вывести диапазон строк, делаешь так:<br><br><pre>bat -r 20:25 ~/bashdays.sh<br><br></pre><em>Если ты новичок и не знаешь что такое «~/», это домашний каталог, допустим ты работаешь под пользователем user, и выполнив cd ~ ты попадешь в жопу в /home/user. Посмеялись, поехали дальше.<br><br></em>Чтобы посмотреть список всех поддерживаемых языков и расширений файлов, запускай:<br><br><pre>bat -L<br><br></pre>Основное рассмотрели, у <strong>bat</strong> есть еще куча разных ключей, если есть интерес запускай: <code>bat --help</code> и наслаждайся. Многое можно включить и отключить.<br><br>Я использую <strong>bat</strong> из коробки, без всяких ключей, чисто на просмотр файлов, остальное мне и не нужно.<br><br><strong>В скриптах не рекомендую использовать</strong>, применяй старый проверенный <strong>cat</strong>. А <strong>bat</strong> оставь чисто на просмотр файлов в режиме реального времени.<br><br>Больше подробностей можешь найти на <a href = "stickers/AnimatedSticker.tgs">🐱</a> <a href="https://github.com/sharkdp/bat">официальной github</a> странице. <strong>Там же можешь посмотреть картинки</strong> как это всё выглядит в реальном времени, в этот пост опять ничего не могу вставить, ограничения по символам.<br><br>Лады, рад был тебя видеть. Увидимся наверное завтра.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (1).tgs">🟢</a> <strong>Подпишись: </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-40">

      <div class="body details">
29 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message77">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="29.08.2023 15:11:58 +07">
15:11
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ты всяко слышал или используешь Ansible/Puppet/Chef для размножения своего хозяйства. <strong>Молодец!</strong> Инфраструктура как код — мастхев, но при условии, что код не превращен в кусок спутавшихся спагетти. Как показывает практика, в 99.9% случаев <strong>IaC = IaG</strong> (Infrastructure-as-Govno).<br><br>Ладно, сегодня разговор не про это, сегодня поговорим про то же самое, но сбоку. Ведь <strong>одну задачу можно решать разными способами</strong>.  И сегодня на повестке у нас с тобой маленький и изящный инструмент под названием <strong>Parallel ssh (PSSH)</strong>.<br><br><em>PSSH = это инструмент для запуска одной команды на нескольких серверах, без применения bash циклов. Для bash скриптов и пайплайнов это прям идеальная штуковина. Ну и конечно же для каких-то разовых работ, к примеру если нужно закинуть один файл на несколько серверов.<br><br></em>После установки <strong>pssh</strong>, в комплекте ставятся еще такие утилиты: <strong>pscp</strong>, <strong>prsync</strong>, <strong>pnuke</strong>, <strong>pslurp</strong>. То есть из коробки у тебя еще есть 4 инструмента чтобы параллелить свои джобы под разные задачи.<br><br><strong>Установка стандартная:</strong> <code>apt/yum/brew install pssh<br><br></code>После установки, можешь посмотреть что прилетело в этом пакете: <code>dpkg -L pssh | grep bin<br><br></code><pre>parallel-nuke, parallel-rsync, parallel-scp, parallel-slurp, parallel-ssh<br><br></pre>Для полной автоматизации, тебе нужно прокинуть <strong>public ssh</strong> ключи. Нужно взять ключ с сервера на котором будет запускаться <strong>pssh</strong> и положить на сервера где будут выполняться команды.<br><br><strong>Генерим ключик: </strong><code>ssh-keygen<br><br></code><strong>Закидываем ключики на хосты</strong> с помощью команды, либо переносим ручками:<br><br><pre>ssh-copy-id root@10.222.0.2<br>ssh-copy-id root@10.222.0.3<br><br></pre>Если <strong>public</strong> ключи прописаны корректно, то в дальнейшем при использовании утилит из пакета <strong>pssh</strong>, не будет запрашиваться пароль. Это нам и нужно, это обычная практика.<br><br>Давай теперь рассмотрим <strong>как всем этим добром пользоваться</strong>.<br><br>Для начала тебе нужно создать файл инвентаря, где ты пропишешь все свои сервера на которых нужно что-то делать:<br><br><pre>vim ~/.pssh_hosts_1<br><br></pre>и добавить в него к примеру такое:<br><br><pre>root@10.222.0.2<br>root@10.222.0.3<br><br></pre><strong>Теперь можно запускать!<br><br></strong><pre>parallel-ssh -i -h ~/.pssh_hosts_1 uptime<br><br></pre>Опа! Работает! Утилитка сходила на 2 моих сервера и притащила аптайм. Как ты заметил я запускаю <strong>parallel-ssh</strong> а не <strong>pssh</strong>. Чтобы запускать эти утилиты с коротким именем, нужно создать симлинки или алиасы. Это не критично, больше для удобства. Я голову не грею и запускаю с длинным именем.<br><br>У тебя могут быть несколько файлов <strong>.pssh_stage/prod/test</strong>, допустим для прода, стейджа и тестов, тут сам уже этим наруливаешь и при запуске указываешь какой файл инвентаря использовать через ключ <strong>-h</strong>. Ну а ключ <strong>-i</strong> выводит данные на экран.<br><br><strong>Давай апдейтним пакеты:<br><br></strong><pre>parallel-ssh -h ~/.pssh_hosts_1 -- apt -y update<br><br></pre>Флаг разделитель <code>«--»</code> означает, что команда <strong>pssh</strong> завершена и запущена новая команда. В этом случае разделитель указывает оболочке, что не нужно пытаться анализировать, то что следует после параметров командной строки. <strong>Эту тему рассмотрим в отдельном посте</strong>.<br><br>Остальные утилиты <strong>pscp</strong>, <strong>prsync</strong>, <strong>pnuke</strong>, <strong>pslurp</strong>, делают то же самое что и их собратья, синтаксис аналогичный. К примеру для копирования файла на несколько серверов делаем так:<br><br><pre>parallel-scp -h ~/.pssh_hosts_1 /tmp/bs.txt /tmp<br><br></pre>Аналогично поступаем и с другими утилитами из этого пакета:<br><br><strong>pnuke</strong> = завершить процессы<br><strong>pslurp</strong> = скачать файлы с удаленных хостов<br><strong>prsync</strong> = мощнейшая штука для синка файлов туда-сюда<br><br>Да, обрати внимание, что <strong>pslurp</strong> создаст папки с именем каждого хоста, чтобы туда разложить файлы. На случай если файлы будут иметь одинаковые имена.<br><br>Как я и сказал ранее все эти инструменты очень круто сочетаются с <strong>bash</strong> скриптами и пайплайнами где нужно изобретать циклы. <br><br>Конечно Ansible/Puppet/Chef никто не отменял, но с помощью пакета <strong>pssh</strong>, ты сможешь изобрести что-то своё и главное тебе понятное.<br><br>Кстати в природе существует еще <strong>pdsh</strong> (parallel distributed shell). Но я предпочитаю именно пакет <strong>pssh</strong>, так как он включает в себя еще 4 нужные мне софтины.<br><br><strong>Основное рассмотрели. </strong>Похоже пора перечитать книгу «пиши сокращай», но блин из песни слов не выкинешь. Пардон за простыню, но инфа полезная. Хорошего тебе дня!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-41">

      <div class="body details">
30 August 2023
      </div>

     </div>

     <div class="message default clearfix" id="message79">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.08.2023 15:28:27 +07">
15:28
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вчера я <a href="https://t.me/bashdays/77">упомянул</a> тему с двойным тире в командах. Чтобы в долгий ящик не откладывать давай разберемся, что это за животное такое и как с ним жить.<br><br>Я порой вижу, как опытные админы используют команды в консоли следующим образом:<br><br><pre>ssh root@bashdayz.ru --<br><br></pre>Ты наверняка встречал такое и даже применял бездумно, но <strong>что означает это двойное тире</strong>? Зачем оно? Сейчас покажу на котиках.<br><br><em>Двойное тире означает «флаги командной строки». Оно указывает ssh или другой команде не пытаться анализировать то, что следует после параметров.<br><br></em>Масло масленное. <strong>Погнали на практике покажу</strong>, теория нам не интересна!<br><br>У меня есть такая команда:<br><br><pre>ssh root@bashdayz.ru -- command1 --arg1 --arg2<br><br></pre>Приведенный выше синтаксис указывает <strong>ssh</strong> не пытаться анализировать параметры <strong>arg1</strong> и <strong>arg2</strong> после символа <strong>«--»</strong>. Это гарантирует, что команда <strong>command1</strong> примет <strong>arg1</strong> и <strong>arg2</strong> в качестве аргументов командной строки и выполнится на удаленном сервере.<br><br>Короче говоря мы сообщаем <strong>ssh</strong> - все то, что идет после двойного тире, это не твои параметры и аргументы, <strong>анализировать это НЕ НАДО! СТОП!</strong> Дальше дело за <strong>command1</strong> и его параметрами и аргументами.<br><br>Двойное тире обрабатывается нифига не оболочками <strong>bash/zsh/csh/sh/fish</strong> и т.п. Оно обрабатывается средствами самих программ, но <strong>НЕ всех</strong>. Например <strong>ssh</strong> это умеет делать, как и множество других команд и утилит.<br><br><strong>Рассмотрим другие примеры</strong>. Например, ты не сможешь просмотреть файл с именем <code>--file</code> или <code>-f</code> используя команду <strong>cat</strong>. Проверяем:<br><br><pre>cat --file<br>cat -f<br><br></pre>Опа.<strong> </strong>Ошибка! <strong>cat: unrecognized option --file/f</strong>. Давай теперь передадим двойное тире:<br><br><pre>cat -- --file<br>cat -- -f<br><br></pre>Еее! Ошибка пропала и файл успешно вывелся на экран, ну либо выскочило сообщение <strong>cat: --file/f: No such file or directory</strong>. Это нормально.<br><br><strong>Закрепим:<br><br></strong><pre>rm --file       = получим ошибку<br>rm -- &apos;--file&apos;  = а вот это сработает<br><br></pre>Ну а что бы передать параметры в <strong>rm</strong>, делаем так:<br><br><pre>rm -v -i -- &apos;--file&apos;<br>rm -f -v -i -- &apos;-f&apos;<br><br></pre><strong>Просто, логично, мелодично</strong>. Но как я и сказал выше, не все команды умеют работать с двойным тире. Например, команда <strong>echo</strong>, на все попытки подружить её с двойным тире, просто-напросто провалятся:<br><br><pre>/usr/bin/echo -- -n<br>echo -- --test<br><br></pre>выведется это:<br><br><pre>-- -n<br>-- --test<br><br></pre>Да и в принципе всё на этом. Важную и полезную тему разобрали, теперь ты знаешь что это за зверюга и как её применять. <strong>Ставь лайк, делись с друзьями</strong>. Не смею тебя больше отвлекать, пойду дальше дебажить пайплайны. Покеда!<br><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-42">

      <div class="body details">
3 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message80">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="03.09.2023 16:58:40 +07">
16:58
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Войти в сентябрь было непросто, но большую часть задач удалось успешно закрыть. В очередной раз убеждаюсь, что не стоит давать разработчикам root доступ к серверам. Эта оплошность стоила мне 3х дней безвылазного дебага на проде и кучи нервов. Ладно, всякое бывает. <strong>Сегодня поговорим про статусы выхода в bash.<br><br></strong>Каждая программа в linux возвращает некий статус, был ли успех по завершению или возникла ошибка. Этими статусами можно гибко управлять в своих <strong>bash</strong> скриптах для отображения нужных ошибок.<br><br>К примеру мой вело-скрипт для бэкапов основан на команде <strong>tar</strong> и в какой-то момент оно начало возвращать ошибку. Бэкапы соответственно перестали делаться, но я про это ничего не знаю. Но добавив в скрипт обработку ошибок, я получил неплохой триггер, который в случае факапа накричит мне в телеграм. А я успешно это прочитаю и забью болт <a href = "video_files/sticker (52).webm">📺</a> рабочие будни.<br><br><strong>Статус выхода</strong>, это целое число от <strong>0-255</strong>, где <strong>0</strong> это успешное завершение команды/программы. Все остальные коды, это ошибки. <br><br>Например, если программа не найдена ни в одном из путей <code>$PATH</code> либо ее вообще нет в системе, то оболочка вернет <strong>127</strong> код ошибки. Ну а если команда/программа найдена, но не является исполняемой, то мы получим код <strong>126</strong> (Permission denied).<br><br><em>Чтобы сделать программу/скрипт исполняемым, ставь специальный аттрибут: chmod +x &lt;program/script&gt;<br><br></em><strong>Как отловить код выхода из программы/скрипта<br><br></strong>Все очень просто, существует специальная зарезервированная переменная <strong>«$?»</strong>, которая будет хранить в себе как раз тот самый код выхода. Теперь наглядно, запускаем:<br><br><pre># date<br># echo $?<br>0<br><br></pre>Видим что прилетел <strong>0</strong>, окей, команда отработала успешно. Теперь запустим так:<br><br><pre># bashdays<br># echo $?<br>127<br><br></pre>Как видим вернулся код <strong>127</strong>, как я писал выше, этот код означает, что не удалось найти программу с именем bashdays.<br><br>Понятно? Думаю вообще все прозрачно. Имея эту информацию, можно строить гибкую логику в скриптах и обрабатывать эксепшены.<br><br>Чтобы сохранить код в обычную переменную, делаем так:<br><br><pre>#/bin/bash<br><br>date<br>code=$?<br>echo &quot;exit code : ${code}&quot;<br><br></pre>Теперь в переменной <strong>code</strong> будет храниться код завершения. Даже если ты запустишь следом другие команды, в переменной <strong>code</strong> будет лежать предыдущий код выхода.<br><br><strong>Рассмотрим ситуацию с логикой</strong>:<br><br><pre>#!/bin/bash<br><br>date<br>code=$?<br><br>if test $code -eq 0<br>then<br>  echo &quot;success&quot;<br>else<br>  echo &quot;failed&quot;<br>fi<br><br></pre><em>test - предназначена для проверки типа файла и сравнения чисел и строк. Возвращает код возврата 0 (истина) или 1 (ложь) в зависимости от вычисления выражения. Выражения могут быть как унарными, так и бинарными.<br><br></em>Если команда <strong>date</strong> вернет <strong>0</strong> (<strong>-eq</strong> - означает равно), скрипт завершится со статусом <strong>0 = success</strong>, во всех других статусах мы получим <strong>failed</strong>.<br><br>Так же ты можешь самостоятельно возвращать нужные тебе коды в своих скриптах. Я использую этот способ в пайплайнах, когда gitlab считает что завершил сборку успехом, но на самом деле это не так. Подкидываешь ему <strong>exit 1</strong> и пайплайн уже не зеленый, а красный.<br><br><strong>Рассмотрим пример:<br><br></strong><pre>#!/bin/bash<br><br>date<br>time<br>exit 1<br>echo &quot;hello&quot;<br><br></pre>После запуска, выполнятся две команды <strong>date</strong> и <strong>time</strong>, затем всё завершится с кодом 1 не передав управление команде <strong>echo</strong>.<br><br>Применения <strong>exit</strong> очень удобно для дебага, работает как <strong>breakpoints</strong>, вставляешь <strong>exit</strong> где нужно завершить скрипт и вся оставшаяся логика не выполняется. Можно конечно ненужный кусок кода просто закомментировать, но согласись проще вписать <strong>exit</strong> не трогая ничего остального.<br><br>Тема вроде очень простая, но всегда вызывает вопросы и недоумение — В смысле код ошибки? Какой еще <a href = "video_files/sticker (53).webm">🤒</a> ошибки? А что так можно было?<br><br>Короче говоря имея на руках код завершения, можно проверять результаты выполнения команд и тригерить что-то нужное.<br><br>Давай краба, завтра увидимся, хорошо тебе догулять выходные!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-43">

      <div class="body details">
4 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message81">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="04.09.2023 20:21:49 +07">
20:21
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Йоу-Йоу и снова ваш покорный сеньор у микрофона. Короче писал, писал я вам сегодня интересный пост, про офигительные циркули, но прибежало начальство и нагрузило какой-то шляпой, сижу вот плачу. В общем доведу до ума портянку и завтра уже вечерком закину.<br><br>Сегодня мини пост. <a href="https://t.me/bashdays/80">Вчера</a> мы с тобой обсуждали коды выходов программ/скриптов. Давай теперь затронем тему <strong>mysql</strong>, а конкретнее <strong>как расшифровать коды ошибок</strong>, которые пишутся в лог без пояснений.<br><br><strong>Смотрим mysql ошибки:<br><br></strong><pre>tail -n 20 /var/log/mysql/error.log<br><br></pre><em>Команда tail записывает в стандартный поток вывода содержимое файла, заданного в параметре файл, начиная с указанной позиции.<br><br></em>Ключ <strong>-n</strong> = количество строк с конца, которые выведутся на экран, по умолчанию 10.<br><br>Так, получили 20 строчек с ошибками, смотрим что же там, опа ошибка:<br><br><pre>11:47:52 [ERROR] mysqld: Can&apos;t open file: ‘/var/lib/mysql/tokens.frm&apos; (errno: 24)<br><br></pre>О чем она мне говорит? Ну ясно понятно - не могу открыть файл <strong>tokens.frm</strong>. Идем смотреть, хм, файл лежит на месте и даже не нулевого размера. Права правильные mysql:mysql. Так… место на диске тоже предостаточно. И что ты от меня хочешь псина?<br><br><em>Важный совет — всегда читай ошибку с начала и до конца! В 99% ты сможешь понять о чем идет речь и загуглить. Но как показывает практика: много кто читает 2-3 слова и бежит к тимлиду — Наташа, у нас все сломалось! А Наташа смотрит тот же самый лог и прекрасно понимает в чем дело. Не беси своего тимлида! Читай внимательно, вникай.<br><br></em>Вернемся к нашей неочевидной ошибке с открытием файла <strong>tokens.frm</strong>. Видишь в конце строки, в скобочках <strong>errno: 24?</strong> <strong>ВОТ ЭТО ОНО!</strong> А что значит <strong>24</strong>? Ща…<br><br>Из коробки с <strong>mysql</strong> идет прекрасная утилита, которая называется <strong>perror</strong>, вот с помощью нее ты и можешь расшифровать эту ошибку. Давай попробуем.<br><br><pre>perror 24<br>OS error code  24:  Too many open files<br><br></pre>Ёпта! <strong>Too many open files</strong>, а мы то всего-навсего уперлись в <strong>open_files_limit</strong> который прописан в конфиге <strong>my.cnf</strong>. <strong>Дело закрыто!</strong> Увеличиваем этот параметр и гордимся своими профессиональными навыками дебагинга.<br><br>Увеличение этого параметра может и не спасти ситуацию, тогда проблема в <strong>ulimit</strong>, смотрим какое в нем число и по возможности увеличиваем. Подробно про <strong>ulimit</strong> расписывать не буду, закинул в беклог, обязательно поговорим о нем следующих постах.<br><br>Еще есть прекрасный файл <strong>/etc/security/limits.conf</strong> в котором тоже может быть что-то не так накручено, ну и параметр <strong>fs.file-max</strong> в <strong>/etc/sysctl.conf</strong>. Каждая отдельная ситуация индивидуальна. Но в большинстве случаев решается повышением значения <strong>ulimit</strong>.<br><br>Для каждого кода ошибки в <strong>mysql</strong> будет свой способ решения, чем больше у тебя информации на руках, тем больше запросов ты сможешь загуглить. Так что если что-то упало, не рви на <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">жопе</span></span> себе волосы, всё решаемо и ты обязательно справишься! Главное знать какой инструмент и когда применить.<br><br>Ладно, надеюсь было полезно, пойду дальше плакать. Завтра залетит интеграция от партнера, ну а вечером уже закину пост про офигительные циркули. Давай!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;mysql&quot;)">#mysql</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-44">

      <div class="body details">
5 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message83">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.09.2023 19:25:21 +07">
19:25
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Про офигительные циркули. Порой бывает устанавливаешь какую нибудь софтину на linux, а впридачу с ней идет огромный example конфиг. Этим конфигом можно пользоваться по дефолту, либо тонко настраивать. Например, конфиг от <strong>php.ini</strong> весит <strong>80 килобайт</strong>. И больше половины в этом конфиге - комментарии и шляпа.<br><br>А хочется сделать из этого конфига простенький шаблон например для <strong>ansible</strong>, но без лишнего мусора. Чтобы было основное, что позволит софтине вообще запуститься (пути, логи, сокеты и т.п.). Руками выкашивать 60-70 килобайт, то еще занятие. <br><br>Но что если сделать свой собственный маленький парсер? Который выкосит все ненужное и оставит необходимый минимум. <strong>Да, прям на bash! Погнали зажигать!<br><br></strong>Для примера будем работать с тем же файлом <strong>php.ini</strong> и приведем его в юзер-френдли вид.<br><br><strong>Накидываем скрипт:<br><br></strong><pre>#!/bin/bash<br><br>sep=$2<br><br>while IFS= read -r var<br>do<br>  [[ $var =~ ^$sep.* ]] || [[ ! $var =~ &apos; &apos; ]] &amp;&amp; continue<br>  echo &quot;$var&quot; &gt;&gt; $1.tpl<br>done &lt; $1<br><br></pre><strong>Запускаем так: <br><br></strong><pre>./script.sh php.ini &quot;;&quot;<br><br></pre>Передаем 2 параметра. <strong>Первый</strong> = имя файла-конфига, который будем читать и парсить. <strong>Второй</strong> = символ, которым комментируются строки в этом файле.<br><br>В моем случае комментарии в файле идут после <strong>«;»</strong> символа. Обращаем внимание, что второй параметр передаем в кавычках. Если передать напрямую, то оболочка <strong>bash</strong> не поймёт что от нее хотят и выпадет в panic.<br><br><strong>Разбираем скрипт:<br><br></strong>Присваиваем переменной <strong>sep</strong>, символ, который передали <strong>вторым</strong> параметром <strong>$2</strong>. У меня это символ <strong>«;»</strong>.<br><br><strong>Далее идет цикл</strong>, который <strong>построчно читает</strong> файл <strong>php.ini</strong> переданный в первом параметре <strong>$1</strong> при запуске скрипта. Тут универсально, можешь любой файл передать, скрипт его сам схавает как нужно.<br><br><em>IFS= разделяет строку с использованием символа в качестве значения<br><br></em><strong>Ну и логика цикла:<br><br></strong>Если первый символ <strong>равен символу «;»</strong>, который уже лежит в переменной <strong>sep</strong> ИЛИ первый символ <strong>равен пустой строке</strong>, ТО передаем управление команде <strong>continue</strong>, которая проигнорирует запись в <strong>output</strong> файл. И так по кругу, пока не закончится файл.<br><br><em>Команда continue пропускает оставшиеся команды внутри тела цикла для текущей итерации и передает управление программой к следующей итерации цикла.<br><br>Символ || означает = ИЛИ<br><br></em><strong>ВО ВСЕХ ДРУГИХ СЛУЧАЯХ</strong>, происходит запись в <strong>output</strong> файл, в котором будут содержаться только необходимые для работы параметры.<br><br>На выходе получится <strong>2х</strong> <strong>килобайтный</strong> файл <strong>php.ini.tpl</strong>, без комментариев и прочего шлака. Чистый как слеза.<br><br><strong>80 килобайт  vs 2 килобайта!</strong> Ха! Разница ощутима, теперь можно сделать шаблончик для ansible/puppet/chef.<br><br>В своем скрипте я использую <strong>простые регулярные выражения</strong>. ДА! В bash это можно делать через символы <strong>«=~»</strong>.<br><br><pre>$var =~ ^$sep.*<br><br></pre><strong>^ =</strong> соответствует началу текстовой строки<br><strong>$sep = </strong>символ с помощью которого комментируют строки<br><strong>.* =</strong> оставшийся кусок строки<br><br>А можно еще другим способом определять начинается ли строка с определенного символа. Но конкретно с разделителями <strong>«;»/«#»</strong> это будет работать не корректно.<br><br><pre>[[ $var = Y* ]] &amp;&amp; echo &quot;String start with Y&quot;<br><br></pre>В примере выше, происходит проверка, <strong>является ли первый символ в строке символом «Y»</strong> и если да, то <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">пезда</span></span>, выводится соответствующее сообщение. Регулярок тут нет, чисто «*» правит балом.<br><br><strong>Такие дела.</strong> И без применения всяких <strong>sed/бред/винегрет</strong>. Нативно, на <strong>bash</strong>, даже с регулярками научились взаимодействовать, а регулярки развязывают на многое руки. В пределах разумного, не нужно brainfuck создавать.<br><br><em>Brainfuck — один из эзотерических языков программирования, придуман Урбаном Мюллером<br><br></em>Я рассмотрел ситуацию с созданием шаблона, но этот метод парсинга применим вообще под любые задачи, где нужно определить является ли первый символ тем, который тебе нужен. Бери на вооружение.<br><br>Завтра сделаем паузу, а в четверг и в пятницу еще немного поэкспериментируем. Давай! Пока-пока!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message84">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.09.2023 21:08:02 +07">
21:08
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media_poll">

         <div class="question bold">
Коллеги, включаем комментарии к постам?
         </div>

         <div class="details">
Anonymous poll
         </div>

         <div class="answer">
- Да
         </div>

         <div class="answer">
- Нет
         </div>

         <div class="total details&#x09;">
1362 votes
         </div>

        </div>

       </div>

      </div>

     </div>

     <div class="message service" id="message-45">

      <div class="body details">
7 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message85">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.09.2023 15:31:05 +07">
15:31
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
В Linux есть масса утилит, для поиска файлов. К примеру всем известный монструозный <strong>find</strong>, который умеет даже тапочки приносить.<br><br>Но что, если мне нужно <strong>просто найти какой-то файл</strong>? Использовать <strong>find</strong> для такой простой задачи, это явно стрельба из пушки по воробьям. Для таких задач, как моя, есть более изящные решения.<br><br>И это решение, <strong>утилита locate. <br><br></strong><em>Утилита locate используется для поиска файлов, расположенных на машине пользователя или на сервере. Фактически она выполняет ту же работу, что и команда find, однако, ведёт поиск в собственной базе данных.<br><br></em>Ключевая фраза здесь - <strong>в собственной базе данных</strong>. То есть применяя утилиту <strong>locate</strong>, поиск файлов будет осуществляться не по файловой системе, как это делает <strong>find</strong>. А будет использоваться собственная база данных. Коротая позволяет искать файлы со скоростью света.<br><br>Обновление базы данных <strong>locate</strong> происходит автоматически, как правило, раз в сутки. Либо можно запустить руками командой <code>updatedb</code>.<br><br><strong>Давай теперь потыкаем, запускай:<br><br></strong><pre>locate txt<br><br></pre>Ищем <strong>все файлы, имена которых содержат «txt»</strong>. Опа, меньше чем за секунду команда нашла все подходящие файлы, которые можно было найти. А если сделать это через <strong>find</strong>, то это у меня это заняло 18 секунд. Разница очень ощутимая.<br><br>Ищем <strong>файлы, которые оканчиваются на «txt»<br><br></strong><pre>locate &apos;*txt&apos; <br><br></pre>А теперь давай посчитаем <strong>общее количество файлов</strong>, которые нашлись<br><br><pre>locate -ic &apos;*txt&apos; <br><br></pre>Ключ <strong>-i</strong> = режим регистронезависимости<br>Ключ <strong>-с</strong> = вывести общее количество найденных файлов<br><br><strong>Полезли в кишки, заводим strace</strong>.<br><br>Переходим в папку <strong>cd </strong><a href="" onclick="return ShowBotCommand(&quot;tmp&quot;)">/tmp</a> и создаем подопытный файл: <code>&gt; hello.txt<br><br></code><em>Знал же что пустой файл можно создать через символ «&gt;»? Если нет, то теперь знаешь.<br><br></em>Так, я нахожусь в папке <strong>tmp</strong> и у меня создан файл <code>hello.txt</code> запускаю:<br><br><pre>locate *txt<br><br></pre><strong>Опа, ничего нет, как так?</strong> Мы же уже запускали ранее это, чтобы найти все файлы, которые заканчиваются на <strong>txt</strong>. Что случилось?<br><br>Мы вызываем внешнюю команду <strong>locate</strong>, но вызываем мы ее из интерпретатора <strong>bash</strong>. Вернее её вызывает сам интерпретатор. И это накладывает свои нюансы. В нашем случае этот нюанс <strong>«Подстановка имен файлов»</strong>, то есть <strong>Globbing</strong>.<br><br><strong>Сейчас будет сложно для понимания, но чуть ниже я разжую на человеческий.<br><br></strong><em>Во времена UNIX V6, существовала программа /etc/glob, которая могла раскрывать шаблоны подстановки. Очень скоро она стала встроенной функцией командной оболочки.<br><br></em>Но что же случилось то в итоге, <strong>почему ничего не нашлось?</strong> <strong>А произошло следующее:</strong> после того, как интерпретатор обнаружил символ <strong>«*»</strong>, который является спецсимволом и соответствует любой строке, интерпретатор попытался сделать подстановку <strong>Globbing</strong> и ему это удалось. <br><br>И при вызове команды <strong>locate</strong> она получила в качестве аргументов, результат этих подстановок. Давай посмотрим наглядно что произошло. Запускаем:<br><br><pre>strace -e execve locate *txt <br><br></pre>На выходе получаем:<br><br><pre>execve(&quot;/usr/bin/locate&quot;, [&quot;locate&quot;, &quot;hello.txt&quot;], 0x7ffe242252d8 /* 27 vars */) = 0<br><br></pre>Опция <strong>«e»</strong> и аргумент <strong>«execve»</strong> сообщают <strong>strace</strong>, что я хочу отслеживать только системные вызовы <strong>«execve»</strong>.<br><br><em>execve() выполняет программу, заданную параметром filename<br><br></em>Возвращаемся к выводу от <strong>strace</strong> и видим что <strong>locate</strong> получила в качестве аргумента<code> hello.txt<br><br></code>И теперь <strong>locate</strong> будет искать  файлы именно по этому шаблону, а не по тому, что мы с тобой ожидали, когда писали<strong> «*txt».<br><br></strong>Вот лишь по этому на экран ничего не вывелось, когда я запустил <code>locate *txt<br><br></code>А чтобы этого не происходило <strong>всегда используй quoting (кавычки)</strong> и будешь получать ожидаемый результат.<br><br><pre>locate &apos;*txt&apos; <br><br></pre>Механизм подстановки имен файлов (<strong>Globbing</strong>) на самом деле удобен, просто нужно использовать его по назначению.<br><br>Если ты это усвоил, то уже не наступишь на грабли. Да и <strong>strace</strong> снова немного затронули, можешь применять для дебага и смотреть что происходит внутри, после вызова той или иной команды.<br><br>Поигрались и хватит. Пошли дальше работу работать. <strong>Всех был рад видеть, пока-пока!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;strace&quot;)">#strace</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-46">

      <div class="body details">
8 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message87">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.09.2023 18:07:06 +07">
18:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Здарова! У меня на машине имеется пачка всяких alias’ов для продуктивной работы. К примеру есть такой <code>alias cat=&apos;batcat’</code>. <br><br>Я привязал команду <strong>cat</strong> к нужной мне утилите. В данном случае это <strong>batcat</strong>. Про нее я рассказывал в <a href="https://t.me/bashdays/75">предыдущих постах</a>.<br><br>Все работает отлично, но что мне делать когда требуется деактивировать этот <strong>alias</strong> и воспользоваться чистой командой <strong>cat</strong>? <br><br>Ты скажешь - дак залезь в файл <strong>~/.bashrc/.zshrc</strong> да закомментируй всю эту срамоту. Справедливо! Но это какое-то топоровое решение.<br><br>Есть несколько вариантов как это осуществить нативно и красиво. Ща покажу.<br><br><em>Посмотреть все прописанные alias, можно через одноименную команду alias, выведется полный список.<br><br></em><strong>Первый вариант<br><br></strong>Перед командой ставим символ <strong>«\»</strong>:<br><br><pre># \cat /tmp/test.txt<br><br></pre>И всё! Теперь в моем случае <strong>alias</strong> с <strong>batcat</strong> проигнорирован и сработала нативная утилита <strong>cat</strong>. Красота!<br><br><strong>Второй вариант<br><br></strong>Помещаем команду в кавычки, хоть в двойные хоть в одинарные:<br><br><pre># &apos;cat&apos; /tmp/test.txt<br># &quot;cat&quot; /tmp/test.txt<br><br></pre>Результат будет таким же, как и в первом варианте. Алиас заигнорится, запустится коробочный <strong>cat</strong>.<br><br><strong>Третий вариант<br><br></strong>Капитанский вариант с указанием полного пути к команде:<br><br><pre># /usr/bin/cat /tmp/test.txt<br><br></pre>Ну тут всё логично, я четко указал что и откуда запускать. Алиасы в пролете. Нативочка в профите.<br><br>Чтобы узнать полный путь к команде, воспользуйся одним из этих способов, они очень часто встречаются в bash скриптах, я приводил пример в <a href="https://t.me/bashdays/38">этом</a> посте.<br><br><pre>whereis cat<br>which cat<br>type -a cat<br><br></pre><strong>Четвертый вариант<br><br></strong>С помощью команды <strong>command<br><br></strong><pre># command cat /tmp/test.txt<br><br></pre><em>Команда command заставляет оболочку рассматривать указанную команду и аргументы как простую команду, подавляя поиск функций оболочки, или отображает информацию о заданных командах.<br><br></em><strong>Пятый вариант<br><br></strong>Этот вариант пожалуй более глобальный, который отключает алиасы в текущем сеансе. Не удаляет, а именно <strong>«анлиасит»</strong> в текущей сессии.<br><br><pre># unalias cat<br><br></pre>Хаба-хаба и всё! Теперь у нас в текущей сессии чистый <strong>cat</strong>, без хвостатых мышек сюси.<br><br>А чтобы вообще <strong>дропнуть все алиасы в текущей сессии</strong>, запускай такое:<br><br><pre># unalias -a<br><br></pre>Ну вот и все, теперь вообще никаких alias’ов нет, голый король. Ну а чтобы не перезапускать сессию и восстановить как было, делаем так:<br><br><pre>source ~/.bashrc<br>source ~/.zshrc<br><br></pre>Возможно в природе есть еще какие-то варианты, но тебе и этих пяти штук будет за глаза. <br><br><strong>Я использую первый вариант</strong>, он достаточно быстрый и менее трудозатратный. Ну а если что-то дебажу, то применяют пятый вариант. Для чистоты экспериментов, чтобы на грабли не наступить там где не нужно. <br><br><strong>С пятницей коллеги! Хороших тебе предстоящих выходных и береги себя!</strong> Пойду дальше мемы для <a href="https://t.me/+qo5d6KDzahxlNjBi">Псины</a> рисовать, забегай если скучно.<br><br><em>Спасибо всем проголосовавшим в </em><a href="https://t.me/bashdays/84">этом</a><em> посте, большинство ЗА, так что в ближайшее время прикручу комменты. Но терзают меня пока сомнения, в общем решим этот вопрос. Увидимся!<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-47">

      <div class="body details">
11 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message88">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.09.2023 15:59:48 +07">
15:59
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет коллега! Надеюсь ты выжил после выходных и не сорвал спину на мероприятии по копке картофеля. <strong>Сегодня у нас с тобой bash</strong>.<br><br>Мы прекрасно знаем, что <strong>bash</strong> скрипты выполняются последовательно. Но есть ли <strong>способы запускать команды параллельно?<br><br></strong>Конечно есть, сейчас про это и поговорим. Покажу два способа как это можно легко осуществить. Первый способ основан на символе <strong>&amp;</strong>.<br><br><strong>Пишем подопытный скрипт:<br><br></strong><pre>#!/bin/bash<br><br>sleep 5 &amp;&amp; echo &quot;sleep 5_1&quot; &amp;<br>sleep 5 &amp;&amp; echo &quot;sleep 5_2&quot; &amp;<br>wait<br>echo &quot;sleep 0&quot;<br><br></pre>Здесь <strong>первая</strong> и <strong>вторая</strong> команда <strong>запустятся параллельно</strong>. Через 5 секунд на экран выведутся 3 строчки <strong>sleep 5_1</strong>, <strong>sleep 5_2</strong> и <strong>sleep 0.<br><br>Wait </strong><em>– команда, которая ожидает завершения определенного процесса, а затем возвращает его состояние завершения.<br><br></em>Оболочка ждет (<strong>wait</strong>) пока завершатся два предыдущих процесса, прежде чем запустить следующую команду. Получается, все то, что в скрипте идет после <strong>wait</strong>, будет в режиме ожидания, пока не завершится первый <strong>sleep</strong> и второй.<br><br><strong>Прикольно да?</strong> Открываются новые возможности для совершенствования своих костылей. Прям терпко попахивает асинхронностью, в хорошем смысле. Про <strong>wait</strong> поговорим в отдельном посте, есть там свои клевые фичи.<br><br>Теперь давай запустим в терминале последовательно такие команды:<br><br><pre>sleep 60 &amp;<br>sleep 90 &amp;<br>sleep 120 &amp;<br><br></pre>На экран выведутся записи вроде таких:<br><br><pre>[1] 38161<br>[2] 38166<br>[3] 38167<br><br></pre>Это <strong>PID</strong> процессов которые ты запустил в фоновом режиме. Но интересует нас тут другое. А именно команда <strong>jobs</strong>.<br><br><em>Команда jobs в Linux позволяет пользователю напрямую взаимодействовать с процессами в текущей оболочке. Команда отображает состояние заданий в текущем сеансе.<br><br></em>Запускаем <strong>jobs</strong> и смотрим:<br><br><pre>[1]   Done    sleep 60<br>[2]-  Running sleep 90 &amp;<br>[3]+  Running sleep 120 &amp;<br><br></pre>Опа! А это список команд, которые мы запустили в фоне. Первое задание завершилось, остальное еще шуршит. Некий мониторинг из коробки.<br><br>Давай теперь напишем <strong>более наглядный пример</strong>, где всё это можно применить.<br><br><pre>downloader(){<br>  wget -q &quot;$1&quot;<br>}<br> <br>while IFS= read -r url<br>do<br>     downloader &quot;$url&quot; &amp;<br>done &lt; urls.txt<br> <br>wait<br>echo &quot;Downloaded complete&quot;<br><br></pre>1. Скрипт читает построчно файл <strong>url.txt<br></strong>2. Передает каждую строчку в функцию <strong>downloader<br></strong>3. Функция <strong>downloader</strong> каждый раз запускается в фоне<br>4. Происходит скачивание файла по ссылке<br>5. По завершению (<strong>wait</strong>) получаем <s>компливит</s> <strong>complete<br><br></strong>Файл <strong>url.txt</strong> представляет собой список прямых урлов на файлы, которые нужно скачать.<br><br>Получается мы не дожидаемся пока скачается первый файл, а сразу скачиваем все пачкой. <strong>Мультизагрузка</strong>.<br><br>Если совсем уж по-простому, то символ <strong>&amp;</strong> говорит — запусти всё одновременно и параллельно. Типа такого, с таким ты уже всяко встречался:<br><br><pre>hostname &amp; date &amp; uname &amp;<br><br></pre>Тут все запустится одновременно и порядок вывода на экран будет каждый раз в своем порядке. Все зависит с какой скоростью отработает команда.<br><br><strong>Это основной вариант, советую его и использовать</strong>, теперь давай рассмотрим альтернативные.<br><br>Есть еще такая утилита <strong>parallel</strong>, устанавливается как и все остальное <code>apt/yum/brew install parallel<br><br></code>Делает она то же самое, но имеет более гибкие настройки через параметры. Например, предыдущий пример со скачиванием файлов мог бы выглядеть таким образом:<br><br><pre>parallel -j 4 wget -q {} &lt; urls.txt<br><br></pre>Ключ <strong>-j</strong> означает сколько джобов будет запараллелено, что-то типа потоков/threads.<br><br>Углубляться сейчас в <strong>parallel</strong> особого смысла не вижу, но для общего кругозора ты про нее должен знать. Иногда бывает что для решения задачи подойдет именно <strong>parallel</strong>, а не нативка с <strong>&amp;.<br><br>Ну и на закуску</strong>, есть такая штука <strong>«$!»</strong>, она позволяет узнать PID последнего запущенного процесса. Давай на примере, запускай:<br><br><pre>sleep 60 &amp;<br>[1] 39032<br>echo $!<br>39032<br><br></pre>В первой команде запустили фоном ожидание 60 секунд, вывелся порядковый номер джобы и <strong>PID</strong>. Ну а чтобы получить последний <strong>PID</strong>, выполняем третью команду с <strong>«$!»</strong>. На экран вывелся <strong>PID</strong> в чистом виде, а дальше можешь его сохранить в переменную и уже проверять в скрипте, завершился он или нет.<br><br>Вот так это и работает. Ничего сложного. Надеюсь было интересно. <strong>Хорошего тебе понедельника, увидимся!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message89">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.09.2023 21:52:12 +07">
21:52
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет еще раз кого не видел. По <a href="https://t.me/bashdays/84">результатам</a> голосования в тестовом режиме <strong>включаю комментарии</strong> к постам, для этого я сделал отдельную <a href="https://t.me/+bZiB4BLuvvZhOWVi">группу</a>. Группа закрытая, по заявкам. Всех заапрувлю руками, чтобы gpt/шл%ха ботов на корню отсечь.<br><br>Кому интересно, <a href="https://t.me/+bZiB4BLuvvZhOWVi">оставляйте заявку</a>. Комменты появятся только к новым постам, такая уж особенность в телеграм.<br><br>Потестим до конца сентября. Если будет толк, то оставим. Ну а если нет, то тоже оставим, но забаним душнил и провокаторов. Я надеюсь будет всем интересно пересечься с единомышленниками и затереть за прекрасное.<br><br><strong>Каждый из вас обладает эксклюзивными знаниями</strong> и иногда так и хочется сказать — да <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">блять</span></span> блин! Это делается вот так! Есть такая утилита, не знал что ли? У тебя тут ошибка, я бы сделал так! Короче <a href="https://t.me/+bZiB4BLuvvZhOWVi">Велком to BASH DAYS|CHAT</a>.<br><br><em>Ну а кто проголосовал против, просто не обращайте внимания на дополнительную кнопку с комментариями, включайте зрительный adblock и наслаждайтесь контентом как и раньше.<br><br></em>Жму руку! Ну и котики: <a href = "video_files/sticker (54).webm">😎</a> <a href = "video_files/sticker (48).webm">😊</a> <a href = "video_files/sticker (55).webm">👍</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-48">

      <div class="body details">
12 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message90">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.09.2023 21:29:00 +07">
21:29
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:15, 1.3 MB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Йо! Мини пост. Хочешь <strong>погонять змея</strong> и ничего при этом не устанавливать? Запускай в консольке:<br><br><pre>bash &lt;(curl -s https://raw.githubusercontent.com/wick3dr0se/snake/main/snake)<br><br></pre>Игруха создана на чистом bash v5.1+. Плюсом можно потренить навигацию в VIM используя hjkl, ну и стрелочки никто не отменял.<br><br>Отлично отключает голову, после восьми часового дебагинга. Денёк сегодня, конечно вообще атас.<br><br>А кто еще какие игрули консольные знает без геморной установки? Кидай в комменты, заценим!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-49">

      <div class="body details">
14 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message91">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="14.09.2023 16:11:10 +07">
16:11
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вчера оказывается столько праздников было, уууу. И день журавля, и день парикмахера, и день пирога и день программиста. Но вместо того чтобы весело пить пиво и есть шарлотку, я как обычно занимался какой-то «очень полезной» шляпой.<br><br>Когда тебе навязывают зеленых стажеров, так или иначе сталкиваешься с шарингом своего экрана. Чтобы наглядно показывать будущему поколению крючочки и закорючки. <strong>Визуально информация усваивается гораздо лучше.<br><br></strong>Раньше я просто шарил экран в гугол мите, но всё это дело было очень прожорливым для моего ноута. Расшариваю я в основном консольку, показываю ребятам какие команды ввожу, что и как запускаю.<br><br>И пришел я однажды к прозрению — <strong>из лука весом в тысячу кан не стреляют по мышам</strong>. Зачем мне какой-то всратый гугол мит? Есть же <strong>прекрасная утилита</strong>, которая называется <strong>tty-share</strong>.<br><br><em>Кан - японская единица измерения массы, равная 10 хиакумэ.</em> <em>Не знаю зачем тебе эта информация, просто живи теперь с ней.<br><br></em><strong>tty-share</strong> - простейший инструмент, который используется для предоставления общего доступа к терминалу Linux/OSX через интернет. Написан на GO и само собой кроссплатформенный без зависимостей. Можно даже на малине (Raspberry Pi) эту чертяку запускать.<br><br><strong>Как это работает. </strong>Идем в терминал и устанавливаем <code>apt/brew install tty-share</code> либо затаскиваем бинарник с <a href="https://github.com/elisescu/tty-share">гитхаба</a>.<br><br>После установки вбиваем и запускаем:<br><br><pre>tty-share --public --readonly<br><br></pre>получаем такое:<br><br><pre>public session: https://on.tty-share.com/mbeD30O8tEoWr4_4/<br>local session: http://localhost:8000/s/local/<br>Press Enter to continue!<br><br></pre>Жмем Enter и погнали! Первая строчка <strong>public session</strong>, она мне и нужна. Копирую <strong>URL</strong> и отдаю стажерам, они вбивают этот <strong>URL</strong> в браузер и видят мою расшаренную консоль.<br><br><strong>Все что я ввожу и запускаю</strong> в своей консоли, <strong>отображается у стажеров в браузере</strong>.<br><br>Ключ <code>--readonly</code> делает так, чтобы «прямые руки» моих подопечных не могли вмешиваться в процесс просвещения. Да, если этот ключ не указать, то стажеры смогут через свой браузер вбивать команды в мою консоль.<br><br><strong>По моему это офигительно!</strong> Работает за любым NAT. Так же есть и локальная сессия (<strong>local session</strong>), если вы находитесь в одной подсети, можно не указывать ключ <code>--public</code> и довольствоваться локалкой.<br><br>У <strong>tty-share</strong> есть масса других возможностей, можно менять порты, пускать через проксю, указывать оболочку (bash/zsh/etc), писать логи и многое другое. Загляни в хелп (<code>--help</code>) если интересно. <br><br>Мне достаточно двух <strong>public</strong> и <strong>readonly</strong>, остальное нафиг, работает и хорошо. По безопасности там <strong>TLS</strong> и <strong>https</strong>, но разработчик обещает добавить сквозное шифрование, пароли и ключи. Подробнее можешь почитать в разделе docs на <a href="https://tty-share.com/">странице</a> проекта.<br><br><strong>А как завершать сессию?</strong> <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">А хуй его знает.</span></span> В доке есть упоминание про ключ <code>-detach-keys</code>, но из коробки <strong>ctrl-o, ctrl-c</strong> не работает, либо я совсем буратино. Поэтому когда мне нужно убить <strong>public session</strong>, я просто сделал себе <strong>alias</strong> на такую команду:<br><br><pre>kill $(ps aux | grep &apos;tty-share&apos; | awk &apos;{print $2}&apos;)<br><br></pre>Если разберешься как нативно прикончить сессию, пиши в комменты, скину тебе картинку с котиком.<br><br>Залил гифки работы tty-share в телеграф, <strong>глянуть можешь </strong><a href="https://telegra.ph/tty-share-09-14">тут</a><strong>.<br><br></strong><a href = "stickers/AnimatedSticker (5).tgs">🔵</a> <a href="https://tty-share.com/">сайт проекта<br></a><a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://github.com/elisescu/tty-share/">репозиторий на github<br><br></a><strong>альтернативы:<br><br></strong>- <a href="https://tmate.io/">Instant terminal sharing<br></a>- <a href="https://learn.microsoft.com/en-us/visualstudio/liveshare/use/install-live-share-visual-studio-code">VSCode Live Share<br><br></a>Пользуйся на здоровье. Хорошего тебе дня, увидимся!<br><br><em>UPD: Наш коллега Egor нашел способ завершить сессию, просто вводишь exit и вуаля! Спасибо Egor!<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-50">

      <div class="body details">
18 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message92">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.09.2023 14:14:42 +07">
14:14
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Задался вопросом <strong>какая же все-таки оболочка быстрее?</strong> У меня на серверах можно встретить такой зоопарк: <strong>sh, bash, ksh, mksh, posh, zsh. </strong>Почему так много? Не знаю, сервера достались по наследству, видимо остатки от давно сгинувших девопсов по реке Стикс.<br><br>На своей локальной машине использую исключительно <strong>zsh</strong> со всякими наворотами:<br><br><a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://ohmyz.sh/">Oh My Zsh</a> - прибомбасина для zsh<br><a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://github.com/zsh-users/zsh-autosuggestions">autosuggestions</a> - автокомплит<br><br>На серверах алогично <strong>Oh My Zsh + autosuggestions</strong> ну и нативный <strong>bash</strong> для скриптов, все остальное — неведомая хрень.<br><br><strong>Автокомплит мастхев</strong>, экономит кучу времени, чтобы не тыкать стрелочку вниз вверх. <strong>Вводишь начало команды</strong> и оно тебе с хистори <strong>автоматом</strong> уже <strong>подгоняет варианты</strong>. Не надо каждый раз упарываться и писать всю команду целиком. Удобно!<br><br>Дополнительно из плагинов включаю <a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://github.com/zsh-users/zsh-syntax-highlighting">zsh-syntax-highlighting</a> чтобы красивенько было. Ну а чтобы каждый раз не указывать <strong>ssh</strong> ключи при подключении к серверам, использую встроенный плагин <strong>ssh-agent</strong>.<br><br><code>plugins=(git zsh-syntax-highlighting zsh-autosuggestions ssh-agent)<br>zstyle :omz:plugins:ssh-agent agent-forwarding on<br>zstyle :omz:plugins:ssh-agent identities home_rsa work_rsa2 her_rsa3<br>zstyle :omz:plugins:ssh-agent lifetime<br><br></code><strong>Вернемся в теме - кто быстрее</strong>. Очевидно же что <strong>bash!</strong> Давай убедимся.<br><br>Запустим этот скрипт в <strong>bash</strong>:<br><br><code>for i in $(seq 1 1000);<br>do bash -c &quot;:&quot; ;<br>done<br><br></code>Запускаем через time: <code>time bash speed.sh<br><br></code><em>time - оценивает по времени производительность любой задачи, выводя после её завершения затраченное время: реальное, пользователя и системы.</em> <em>Через time можешь оценивать производительность по времени любых своих скриптов</em>.<br><br><strong>После запуска получаю:</strong> 0m1.242s<br><br><em>Скрипт отслеживает точное время открытия шелла 1000 раз без выполнения каких-либо операций.<br><br></em>Ок, теперь давай запустим этот скрипт в zsh: <code>time zsh speed.sh<br><br></code><strong>Результат: </strong>0m1.344s<br><br><strong>Не такие и большие различия.</strong> Даже можно сказать ничтожные. Но это всего лишь один тест. Чтобы получить какие-то средние значения воспользуемся утилитой:<br><br><a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://github.com/shellspec/shellbench">shellbench<br><br>Устанавливаем</a><strong> и запускаем:<br><br></strong><code>git clone https://github.com/shellspec/shellbench.git .<br>shellbench -s bash,zsh sample/*<br><br></code>По итогу получаем около 28ми тестов. На <a href="https://telegra.ph/shellbench-09-18">картинке</a> можешь глянуть мои результаты. <strong>Числа в таблице это - количество выполнений в секунду.<br><br></strong>Хм, в совокупности тестов получается что <strong>zsh</strong> где-то прям намного шустрее, да даже ни где-то, а прям почти лидирует в производительности.<br><br>По большей части это писькомерство, ну работает оно и работает, какая разница насколько быстрее. Да, соглашусь, но пару раз встречал ребят которым ставили задачу на оптимизацию выполнения скриптов, где важна каждая секунда. Это как у оверклокеров, где каждый герц и фпс это уже победа.<br><br><strong>Вывод: </strong>По результатам тестов, <strong>zsh</strong> оказался быстрее чем <strong>bash</strong>, но не везде. Опять-же тут все индивидуально.<br><br><em>Кстати когда запускаешь на macos midnight commander + zsh в роле оболочки, то mc запускается прям кое как, секунды три наверное. Поэтому с mc я использую bash, можно конечно этот момент отдебажить, но мне лень. Если когда-нибудь руки дойдут, напишу как пофиксил.<br><br></em>А вообще самая быстрая оболочка это <strong>Dash</strong> (Debian Almquist Shell). Это POSIX-совместимая реализация <strong>Bourne Shell</strong>. Она заменяет <strong>/bin/sh</strong> в скриптах по умолчанию и обеспечивает улучшенную скорость, потребляя при этом меньше ресурсов. <strong>Dash</strong> превосходит <strong>bash/zsh</strong> по производительности, но его нельзя использовать, так как он не предназначен для взаимодействия.<br><br><strong>❓</strong><strong> А какую оболочку используешь ты и почему?<br><br></strong><em>Кстати всем привет! Надеюсь твои выходные прошли без проишествий. Увидимся!<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-51">

      <div class="body details">
19 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message94">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="19.09.2023 15:03:02 +07">
15:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Возможно ли на <strong>bash</strong> <strong>отрендерить</strong> какой-нибудь <strong>шаблон</strong>? Например, как в ansible? Конечно возможно! Сейчас покажу.<br><br>Давай возьмем огрызок конфига <strong>nginx</strong> и сделаем из него шаблон под разное окружение. У меня будет 2 сервера, естественно <strong>production</strong> и до кучи возьмем <strong>stage</strong>.<br><br><strong>Создаем шаблон:</strong> <strong>nginx.tpl<br><br></strong><pre>user ${nginx_user};<br>worker_processes auto;<br>pid ${pid_path};<br>include /etc/nginx/modules/*.conf<br><br></pre>Всё то, что нужно отрендерить, располагаем в <code>${параметр}.<br><br></code><strong>Создаем скрипт с логикой:<br><br></strong><pre>&gt;&gt; nginx_gen.sh &amp;&amp; chmod +x nginx_gen.sh<br><br></pre>Символы <strong>«&gt;&gt;»</strong> означают - создать новый файл. А чмодиком делаем файл покорным и исполняемым.<br><br>Еще есть фича с созданием файла через <code>touch nginx_gen.sh.</code> Если запустить команду с <strong>touch</strong> повторно, то файл не перетрется, НО у него <strong>обновится дата и время создания</strong>. Иногда бывает полезно обновлять дату и время каким-нибудь файлам, которые выполняют роль флагов.<br><br><strong>Так, поехали рендерить:<br><br></strong><pre>#!/bin/bash<br><br>function render {<br>  export nginx_user=$1 pid_path=$2<br>  cat nginx.tpl | envsubst &gt; /etc/nginx/nginx.conf<br>}<br><br>if [[ $(hostname) == &quot;production&quot; ]]; then<br>  nginx_user=&quot;www-data&quot;<br>  pid_path=&quot;/run/nginx.pid&quot;<br>  render $nginx_user $pid_path<br><br>else<br>  nginx_user=&quot;nginx&quot;<br>  pid_path=&quot;/var/run/nginx.pid&quot;<br>  render $nginx_user $pid_path<br>fi<br><br></pre><strong>Разбираем портянку.</strong> Логика простая, если <strong>hostname</strong> равен <strong>production</strong>, то присваиваем одни переменные. Во всех других случаях присваиваем другие переменные.<br><br>Далее вызываем функцию <strong>render</strong> и передаем в нее <strong>nginx_user</strong> и <strong>pid_path</strong>. Функция <strong>render</strong> всё это дело экспортирует в переменные окружения, а затем с помощью <strong>envsubst</strong> заменяет их в шаблоне. Готовый конфиг сразу попадает в папку с <strong>nginx</strong>. <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">Охуенно!</span></span> Кайф!<br><br><em>envsubst - заменяет переменную окружения новым значением в формате строки оболочки командной строки. Переменные могут быть заменены в формате ${var} или $var<br><br></em>Если у тебя много переменных, то можешь их разом экспортировать через цикл. В предыдущих постах у меня где-то есть примеры таких циклов.<br><br>Собственно на этом можно и заканчивать. В 99% случаев все используют какой-то вонючий <strong>perl</strong>, <strong>sed</strong>, <strong>eval</strong> и т.п. Но решение с <strong>envsubst</strong> намного гибче и элегантнее.<br><br>Есть еще вариант с <strong>Heredoc</strong>. <strong>Heredoc-синтаксис</strong> — способ определения строковых переменных в исходном коде программ.<br><br>Пример скрипта, делает то же самое. Логику добавлять не стал:<br><br><pre>#!/bin/bash<br><br>nginx_user=&quot;www-data&quot;<br>pid_path=&quot;/var/run/nginx.pid&quot;<br><br>cat &gt; /etc/nginx/nginx.conf &lt;&lt; EOF<br>user ${nginx_user};<br>worker_processes auto;<br>pid ${pid_path};<br>include /etc/nginx/modules-enabled/*.conf;<br>EOF<br><br></pre>Отрендерится как нужно, но мне все же ближе вариант с <strong>envsubst</strong>. Нагляднее чтоли. Выбор лишь за тобой, на каком велосипеде кататься. Вот такие пироги. Ладно, побежал я дальше работу работать. Будьте здоровы! Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-52">

      <div class="body details">
20 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message96">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.09.2023 14:10:46 +07">
14:10
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_8@20-09-2023_14-10-46.jpg">

         <img class="photo" src="photos/photo_8@20-09-2023_14-10-46_thumb.jpg" style="width: 260px; height: 231px"/>

        </a>

       </div>

       <div class="text">
<strong>Приходила идея спарсить весь github?<br><br></strong>Мне нет! А вот некому <a href="https://github.com/sponsors/anvaka">чуваку</a> такая идея пришла и он <strong>замутил интерактивную карту</strong> по открытым git репозиториям. По итогу коллекция составила более чем 400к репозиториев. Масштабно, ничего не скажешь. <strong>Ну собрал и собрал, нам то какое дело? </strong>Читай дальше!<br><br>А самое главное тут, что под все эти данные, он сделал интерактивную онлайн карту. Каждая «страна» на карте это репозитории, написанные на одном языке или фреймворке. Например, Pythonia = Python, а Swiftoria - на Swift.<br><br>Имена стран генерились с помощью chatgpt таким запросом:<br><br><pre>Please analyze these repository and detect a common theme (e.g. programming language, technology, domain). Pay attention to language too (english, chinese, korean, etc.). If there is no common theme found, please say so. Otherwise, If you can find a strong signal for a common theme please come up with a specific name for imaginary country that contains all these repositories. Give a few options. When you give an option prefer more specific over generic option (for example if repositories are about recommender systems, use that, instead of generic DeepLearning)<br><br></pre><em>Хм, буду теперь названия переменных придумывать таким способом, пусть проклятые роботы за меня пашут.<br><br></em>И даже поиск работает, чудо <a href = "video_files/sticker (18).webm">🍴</a> Можно натолкнуться на достаточно интересные штуки, которые известны лишь узкому числу лиц и особо нигде не пиарятся.<br><br>Потыкать карту можешь: <a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://anvaka.github.io/map-of-github">тут.<br></a>Страница проекта с подробностями: <a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <a href="https://github.com/anvaka/map-of-github">тут.<br><br></a><em>ps: Идея для стартапа: Сделать интерактивную карту с данными pornhub. Чтобы тыкнул и видосики-видосики.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a> <a href="" onclick="return ShowHashtag(&quot;git&quot;)">#git</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message97">

      <div class="body">

       <div class="pull_right date details" title="20.09.2023 14:10:47 +07">
14:10
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_9@20-09-2023_14-10-47.jpg">

         <img class="photo" src="photos/photo_9@20-09-2023_14-10-47_thumb.jpg" style="width: 260px; height: 153px"/>

        </a>

       </div>

      </div>

     </div>

     <div class="message service" id="message-53">

      <div class="body details">
23 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message98">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.09.2023 15:12:42 +07">
15:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем доброе утро, день, вечер, ночь. Наконец-то выходные и слак с моттермостом немного подзаткнулись. Сегодня <strong>рассмотрим ситуацию</strong>, когда ты <strong>случайно/специально удалил исполняющийся bash скрипт</strong>.<br><br><strong>Ситуация:</strong> У меня в фоне на сервере крутится <strong>bash</strong> скрипт, который отслеживает какие-то процессы. Работает годами, но приходит коллега и случайно/специально зачищает папку <strong>/usr/local/sbin</strong>. Опа и скрипта моего больше нет. Мне чо его заново что ли писать? <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">Блять!</span></span> Жопа!<br><br><em>Чтобы не попадать в такие ситуации, всегда храни исходники в git. Соглашусь, что это избыточно, но подложить соломку никогда не будет лишним.<br><br></em>Ладно. <strong>Скрипт мой сгинул</strong>, в <strong>git</strong> я его не положил. <strong>Чо делать?</strong> Так. Скрипт удалён с диска, но <strong>продолжает крутиться в фоне</strong>, это уже хорошо. <strong>Значит его можно</strong> как-нибудь <strong>восстановить</strong>. Сейчас покажу как.<br><br>Давай создадим подопытный скрипт: <code>touch /tmp/script.sh</code> и закинем в него такое:<br><br><pre>#!/bin/bash<br>sleep 1000<br>exit<br><br></pre>Делаем исполняемым <code>chmod +x /tmp/script.sh</code> и запускаем в фоне <code>/tmp/script.sh &amp; <br><br></code><em>Символ &amp; может служить разделителем между командами command &amp; command, две команды выполнятся параллельно.<br><br></em>Так, скрипт запустили, он крутится у нас фоне, давай теперь удалим сам файл:<br><br><code>rm -f /tmp/script.sh</code> ключ <strong>-f</strong> = <strong>force</strong>, удалит без лишних вопросов.<br><br>Окей. <strong>Файл удалили. Как восстановить?</strong> Выполняем:<br><br><pre>lsof -c &apos;script.sh&apos;<br><br></pre>На экран выкатится портянка, нам нужна строка где в конце указан путь до скрипта, который был удален:<br><br><pre>COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME<br>script.sh 261899 root 255r REG 8,1 51 130773 /tmp/script.sh<br><br></pre>Берем <strong>PID</strong> = 261899, берем <strong>FD</strong> = 255 и делаем сальто-мортале:<br><br><pre>cat /proc/261899/fd/255<br><br></pre>Опачки, что мы видим? Исходник скрипта, который мы удалили:<br><br><pre>File: /proc/261899/fd/255<br>#!/bin/bash<br>sleep 1000<br>exit<br><br></pre>Копипастим, вставляем, сохраняем и гордимся своими охренительными скиллами.<br><br>Почему это возможно? А почему бы и нет! В следующих постах расскажу про общую концепцию удаления файлов в Linux и все станет прозрачным.<br><br>Про восстановление файлов на диске, я как-то ранее уже писал <a href="https://t.me/bashdays/48">тут</a>, но там была немного другая история (когда мы знаем <strong>physical_offset</strong>).<br><br><strong>☑️</strong><strong> читать</strong>:<br><pre>man 5 proc # /proc/[pid]/fd/<br>man lsof <br><br></pre><strong>Всем хороших выходных и берегите себя!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

      </div>

     </div>

     <div class="message service" id="message-54">

      <div class="body details">
26 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message100">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.09.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_10@26-09-2023_14-03-01.jpg">

         <img class="photo" src="photos/photo_10@26-09-2023_14-03-01_thumb.jpg" style="width: 260px; height: 103px"/>

        </a>

       </div>

       <div class="text">
Не всегда есть возможность писать <strong>bash</strong> скрипты у себя на локальной машине. К примеру у меня есть ноут где торчит винда чисто под бухгалтерские штуки и мне лень туда запихивать какой-то wsl и т.п.<br><br>Но порой нужно как-то быстренько накидать скрипт и отдать его заказчику, ждать он не будет. Да и бывает в дороге с телефона можно нормально так покодить.<br><br>Для этого я пользуюсь онлайн редакторами-компиляторами, которые отлично интегрированы с <strong>bash</strong>.<br><br>1. <a href="https://rextester.com/l/bash_online_compiler">Rextester</a> - bash version: 4.4.20<br>2. <a href="https://www.mycompiler.io/new/bash">Mycompiler</a> - bash version: 5.1.16<br>3. <a href="https://leetcode.com/playground/new/empty">Leetcode</a> - bash version: 5.0.17<br><br>Я пользуюсь <strong>Mycompiler</strong>, по большей части из-за свежей версии. Все написанные скрипты, можно сохранить в самом сервисе, а также легко поделиться с кем-то по расшаренной ссылке. Ну и есть некое подобие GIT, где можно форкнуться от какого-то своего проекта.<br><br>Помимо <strong>bash</strong>, присутствует еще куча других языков и компиляторов, этакий швейцарский ножик на все случаи жизни.<br><br>Что прикольно, через скрипт можно создать какой-нибудь подопытный файл например <code>echo &quot;test&quot; &gt;&gt; /tmp/test.txt</code> и потом с ним продолжить работу прям из скрипта <code>cat /tmp/test.txt.</code> То есть редакторы позволяют работать с файловой системой и не ограничены лишь компиляцией.<br><br>В общем тыкайте кому интересно. Конечно использование локального <strong>bash</strong> будет более правильным решением, но в каких-то случаях выручают именно онлайн сервисы, тем более они бесплатные. <br><br><em>После интеграции от партнера будет еще один пост на техническую тему, так что далеко не отключайтесь. Да, всем привет! Спасибо ребят, кто </em><a href="https://t.me/bashdays?boost">подбустил</a><em> и дал возможность выкладывать сторисы.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message102">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.09.2023 19:22:18 +07">
19:22
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
И снова привет. Есть такие утилиты <strong>base64/base32/basenc</strong> которые кодируют/декодируют информацию, наверняка ты про них знаешь. Так вот, если утилита встречает во входных данных некорректный символ, она прекращает свою работу. Например:<br><br><pre>echo &apos;!0LPQsNCy0L3Qvg==&apos; | base64 -d<br>base64: invalid input<br><br></pre><strong>А как она понимает какой корректный символ, а какой нет? </strong>А тот который входит в алфавит кодирования. Символ новой строки, также входит в этот алфавит и просто игнорируется утилитой, где бы этот символ не находился.<br><br><em>Алфавит кодирования содержит латинские символы A-Z, a-z, цифры 0-9 (всего 62 знака) и 2 дополнительных символа.<br><br></em>В приведенном выше примере, символ <strong>«!»</strong> не входит в этот алфавит. Чтобы декодировать данные, можно удалить символ восклицательного знака. <strong>Но мы с вами калачи тертые</strong> и любим всё необычное. Поэтому просто указываем ключ <strong>-i</strong> и все символы, которые не входят в алфавит кодирования, просто-напросто будет проигнорирован. <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">Заебись!</span></span> Хорошо!<br><br><pre>echo &apos;!0LPQsNCy0L3Qvg==&apos; | base64 -di<br><br></pre>Опа! И нам тут даже восклицательный знак не помеха, закодированный текст успешно вывелся.<br><br>Вставляя «плохие» символы в закодированную строку, мы можем как бы запретить декодирование. Этакий анти скрипт-кидди получается. Наивный замочек. <br><br><strong>Вставлять «плохие» символы можно в любую часть строки.</strong> При раскодировании с ключом <strong>-i</strong> все эти «плохие» символы будут проигнорированы, где бы они ни были и замочек откроется.<br><br>Типа того (вставил <strong>! </strong>в середину строки):<br><br><pre>echo &apos;0LPQsNC!y0L3Qvg==&apos; | base64 -di<br><br></pre>Закодированная срока успешно раскодируется. А если пойти дальше, можно в обычном тексте передавать закодированные данные:<br><br><pre>echo &apos;Съешь ещё этих мягких французских булок и разжирей 0YXRg9C5&apos; | base64 -di<br><br></pre>Текст в игнор, а данные раскодируются.<br><br>Таким образом можно защищать передаваемые данные между фронтом и бэкендом по API. Отловил кто-то <strong>POST</strong> запрос, выудил из него закодированную строку <strong>base64</strong>, а расшифровать не получается.<br><br>Если тонкостей не знать, на этом все и закончится. Никто особо не будет ковыряться в огромном закодированном тексте и искать, что не так.<br><br>100 лет назад были малвари которые управлялись из твиттера. Малваря заражала машину, потом лезла в твиттер, искала по-индивидуальному хэштегу сообщение, находило его и выполняла инструкции на зараженной машине.<br><br>Сообщение выглядело безобидно, но в конце содержались закодированные команды, с помощью которых и управлялась малваря. Такой способ избавлял злоумышленников от необходимости завязываться на контрольный центр, который в любой момент могли заблокировать по домену или айпишке. Эхх… были времена.<br><br>Ладно, надеюсь было познавательно, всем добра!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-55">

      <div class="body details">
28 September 2023
      </div>

     </div>

     <div class="message default clearfix" id="message103">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.09.2023 15:02:33 +07">
15:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Пум пурум, сегодня еще один <strong>неочевидный способ восстановить удаленные файлы в Linux.</strong> Я знаю, ты такое любишь. Первый способ описывал <a href="https://t.me/bashdays/48">тут</a>, второй <a href="https://t.me/bashdays/98">тут</a>.<br><br>Валяется у меня скриптик <strong>~</strong><a href="" onclick="return ShowBotCommand(&quot;fs&quot;)">/fs</a><strong>.sh</strong>, приходит жопарукий Петя и удаляет его через <strong>rm -rf ~</strong><a href="" onclick="return ShowBotCommand(&quot;fs&quot;)">/fs</a><strong>.sh.</strong> Козлина! Ни о какой корзине речь и идти не может.<br><br>Но я примерно помню, что было внутри. А было там нечто подобное:<br><br><pre>#!/bin/bash<br>echo &quot;Fucking&quot;<br>exit 1<br><br></pre><strong>Что делать?</strong> Ну во первых прописываем прицельную двоечку в безмозглую кабину Пете. Ну а если ты на удаленке, то просто пишем в корпоративную аську — Пётр, вы 3.14дарасина.<br><br>Во вторых запускаем команду:<br><br><pre>grep -a -C 200 -F &apos;Fucking&apos; /dev/sda1<br><br></pre>Оно там подумает какое-то время и начнет вываливать на экран всякий мусор. Ну а среди этого мусора будет удалённый исходник скрипта. Копипастим/Вставляем и снова радуемся своим скиллам.<br><br><strong>Теперь по ключам:<br><br>-a =</strong> осуществляем поиск в бинарных файлах.<br><strong>-C =</strong> сколько строк выводить ДО и ПОСЛЕ каждого совпадения строки.<br><br>То есть у меня совпала строка <strong>Fucking</strong>, если я не укажу <strong>-С 200</strong>, то увижу в выводе только <strong>echo &quot;Fucking&quot;.</strong> А нам то нужно восстановить весь скрипт полностью. Поэтому и нужно сказать грепу, давай еще выведи <strong>200</strong> строк до и <strong>200</strong> после.<br><br><em>Кстати с ключом -C удобно грепать логи какого нибудь php, где нужно посмотреть контекст ошибки, обычно она на несколько строк простилается.<br><br></em><strong>-F =</strong> строка, по которой будем искать.<br><br>Естественно указываем свой раздел диска, у меня это <strong>/dev/sda1</strong>, у тебя может быть что-то совсем другое. Учти этот момент.<br><br><strong>Почему это работает? </strong>Если коротко - мы воспользовались философией Unix, которая гласит — Всё есть файл!<br><br>Такие дела. Чётко и полезно, забирай в копилку знаний. Вечерком еще что-нибудь интересное напишу, пока правда не знаю про что. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;recovery&quot;)">#recovery</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message105">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.09.2023 22:03:10 +07">
22:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
В прошлом <a href="https://t.me/bashdays/103">посте</a> я затронул тему с <strong>grep</strong>, так вот. У <strong>grep</strong> есть хороший ключик <strong>-q</strong>. При указании этого ключа, утилита прекращает свою работу, как только нашлась заданная подстрока. Это <strong>правильная оптимизация</strong> и ей нужно пользоваться если нужно проверить наличие подстроки в файле.<br><br>Давай попрактикуемся и с помощью <strong>strace</strong> посмотрим, как чо там в кишках происходит. Создаем большой файл и забиваем его рандомными данными:<br><br><pre>head -c 1G /dev/urandom &gt; /tmp/large<br><br></pre><em>Если head не понимает буковку G в размере, то указываем явный размер файла: -c </em><code>1073741824</code><em>.<br><br></em>Так, файл размером <strong>1G</strong> готов <strong>/tmp/large</strong>, дальше запускаем:<br><br><pre>strace -P /tmp/large -ye read grep -q &apos;s&apos; /tmp/large<br><br></pre><strong>Ключи:<br>-P</strong> = путь до файла<br><strong>-y</strong> = выводит имя пути до файла<br><strong>-e</strong> = команда которую дебажим<br><br>Через секунду, на выходе получаем нечто подобное:<br><br><pre>read(3&lt;/tmp/large&gt;, &quot;v\310*A\307\16\324m&amp;V8H\202\326\177\244\3059\27}00_\274\300&lt;\245.X\27\310`&quot;..., 98304) = 98304<br>+++ exited with 0 +++<br><br></pre>То есть с опцией <strong>-q, grep</strong> не стал читать полностью весь гигабайтный файл, а сделал лишь один системный вызов <strong>read(3&lt;/tmp/large) </strong>и тут же завершил работу. Искомая строка нашлась, <strong>вернулся статус 0</strong>. Про статусы выхода я писал в <a href="https://t.me/bashdays/80">этом</a> посте.<br><br>Делаем то же самое без <strong>strace</strong> и проверяем статус выхода, все ли идентично:<br><br><pre>grep -q &apos;s&apos; /tmp/large<br>echo $?<br><br></pre><strong>На выходе у нас будет 0</strong>. Ок, эксперимент завершился успехом. Некоторые версии <strong>grep</strong> могут возвращать истину если ошибка произошла не связанная с поиском. Этот момент нужно учитывать. Про такие случаи хорошо написано <a href="https://www.gnu.org/software/grep/manual/html_node/Exit-Status.html#Exit-Status">здесь</a>.<br><br>Если коротко, некоторые версии <strong>grep</strong> с ключом <strong>-q</strong> могут вернуть <strong>статус выхода 2</strong>. Так что на разных системах работать может по-разному. Если в своих скриптах проверяешь эти статусы, логика может сломаться, будь аккуратнее с этим.<br><br><strong>Еще нюанс</strong>, можно добиться такого же поведения <strong>grep</strong>, но без ключа <strong>-q.</strong> Это сработает, если вывод перенаправлен в <strong>/dev/null</strong>. Ну это и логично, нам не нужен никакой вывод на экран и нет никакого смысла продолжать читать огромный файл если подстрока уже найдена.<br><br><pre>strace -P /tmp/large -ye read grep &apos;s&apos; /tmp/large &gt; /dev/null<br><br></pre>Утилита <strong>grep</strong> (без ключа <strong>-q</strong>) так же сделает один системный вызов <strong>read</strong> и прекратит свою работу, как только найдет первое совпадение.<br><br>Вроде не сложно рассказал, по крайней мере попытался. Ладно, рад всех видеть, побежал дальше работу работать, сумасшедший какой-то день. Пока пока!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-56">

      <div class="body details">
2 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message106">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.10.2023 14:32:29 +07">
14:32
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Что-то мало мне было двух выходных, надеюсь хоть ты отдохнул от информационного шума. Ладно, к делу. В <a href="https://t.me/bashdays/62">предыдущем</a> посте мы с тобой рассмотрели линтер для <strong>bash</strong>. А сегодня <strong>познакомимся с утилитой shfmt.<br><br></strong>Это не очередной линтер (но то же умеет орать на ошибки), это <strong>утилита для форматирования и синтаксического анализа скриптов.</strong> Байда написана на <strong>golang</strong> и поддерживает оболочки <strong>POSIX</strong>, <strong>Bash</strong> и <strong>mksh</strong>. Так что утилита не ограничена одним лишь <strong>bash.<br><br></strong>Ставится из пакетного менеджера <code>apt/yum install shfmt</code>. Ну и запускается так же элементарно:<br><br><pre>shfmt script.sh<br><br></pre>Скармливаем утилите свой прекрасный скрипт, а на экран выводится  приятный глазу отформатированный результат. Ну либо не выводится, если встречаются какие-то логические ошибки. Короче утилита выкашивает весь ненужный трешак, но сохраняет <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">«наверное»</span></span> работоспособность скрипта.<br><br>Чтобы каждый раз не копипастить результат форматирования, у <strong>shfmt</strong> есть ключ <strong>-w</strong>, указав его, результат сразу перезапишется в файл над которым проводятся эксперименты.<br><br>Какого-то жесткого кодстайла нет, всё настраивается через ключи, например можно указать количество пробелов и т.п. Закидываем в алиасы и пользуемся.<br><br><em>Я обычно использую shfmt для подготовки скриптов для публикации в публичные репозитории github. Чтобы оупенсорц гуру гавном не закидывали на этапе плохого форматирования.<br><br></em>По секрету скажу, что в личных проектах (да и не только) особо никто не придерживается какому-то определенному форматированию. Все пишут как <s>курица лапой</s> нравится, главное чтобы это работало. Практика плохая, ну лучше плохо чем вообще никак. Да и девчонки плохих любят.<br><br><strong>🐱</strong><strong> Страница проекта на </strong><a href="https://github.com/patrickvane/shfmt">github<br><br></a>Вечером про отладку или обфускацию скриптов поговорим. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message109">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.10.2023 21:09:49 +07">
21:09
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ну чо, расчехляем <strong>strace</strong> и погнали ковыряться в кишках. Сегодня будем проводить эксперимент над утилитой <strong>mktemp</strong>, которая входит в состав пакета <strong>coreutils.<br><br>mktemp</strong>, создает временный файл (по умолчанию) или директорию и возвращает имя созданного файла. Я ее использую для хранения промежуточных данных, когда нужно создать какую-то рандомную папку или файл и положить туда какой-нибудь мусор.<br><br><strong>Задача</strong> - понять что произойдет если временный файл или папка уже существует. Будет ли <strong>mktemp</strong> создавать папку или файл с другим именем и сколько раз она это будет делать. <br><br>Для начала надо узнать <strong>с помощью какого системного вызова создается файл</strong>, запускаем:<br><br><pre>strace -Yyf mktemp<br><br></pre><strong>Y =</strong> выводим команды с привязкой к PIDs<br><strong>y =</strong> выводим пути привязанные к дескрипторам файла<br><strong>f = </strong>мониторим форки процессов<br><br>Можно и без ключей запускать, я просто так привык. После запуска получаем длинную портянку. Мне интересна лишь концовка, а именно:<br><br><pre>openat(AT_FDCWD&lt;/root&gt;, &quot;/tmp/tmp.V0051oIfmC&quot;, O_RDWR|O_CREAT|O_EXCL, 0600) = 3&lt;/tmp/tmp.V0051oIfmC&gt;<br><br></pre>Ага, <strong>отловили openat</strong>. Идем <a href="https://man7.org/linux/man-pages/man2/open.2.html">сюда</a> читать список ошибок которые возвращает <strong>openat</strong>. <br><br>Меня интересует:<br><br><pre>EEXIST pathname already exists and O_CREAT and O_EXCL were used.<br><br></pre>Если были заданы флаги <strong>O_CREAT</strong> и <strong>O_EXCL</strong> и файл существует, то возвращается ошибка <strong>EEXIST</strong>.<br><br>Дополнительно нужно выяснить с какого по счету системного вызова будем перехватывать и возвращать ошибку. Суть в том, что при запуске <strong>mktemp</strong> есть несколько вызовов <strong>openat</strong>. Их делает динамический загрузчик. Если их перехватить, то программа просто не запустится. Также нужно избавиться от нескольких вызовов <strong>openat</strong> которые совершает система языковых переводов. Для этого нужно установить значения переменной <strong>LC_ALL</strong> в <strong>POSIX.<br><br></strong>Выводим все <strong>openat</strong> которые делает утилита:<br><br><pre>LC_ALL=POSIX strace -Yyfe openat mktemp<br><br></pre>У меня получилось 4 строки:<br><br><pre>openat(AT_FDCWD&lt;/root&gt;, &quot;/etc/ld.so.cache&quot;)<br>openat(AT_FDCWD&lt;/root&gt;, &quot;/lib/x86_64-linux)<br>openat(AT_FDCWD&lt;/root&gt;, &quot;/dev/urandom&quot;)\<br>openat(AT_FDCWD&lt;/root&gt;, &quot;/tmp/tmp.eyg53MQ1c2&quot;)<br><br></pre>Вызов создающий временный файл у меня по счету 4й. <strong>Выпускаем кракена:<br><br></strong><pre>LC_ALL=POSIX strace -YCyfe inject=openat:error=EEXIST:when=4+ mktemp<br><br></pre><strong>Вот это поворот! </strong>Ждем какое-то время и наблюдаем, как на экране бежит какая-то дичь. <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">Это твои личные файлы зашифровываются.</span></span> Шутки за 300.<br><br>Короче дождались пока оно там просрется и выведет табличку с результатами. <strong>Смотрим в колонку errors</strong> для системного вызова в <strong>openat</strong> и видим число <strong>238328</strong>.<br><br>Вот собственно столько раз утилита <strong>mktemp</strong> будет пытаться создать файл с новым именем, после того как системный вызов будет возвращать ошибку, означающую что файл существует. Получается количество попыток <strong>62**3 = 238328</strong>.<br><br><strong>Упрямая утилита! </strong>Эксперимент завершен, результат получен, мы молодцы!<br><br>На этом собственно все, немного сложновато, но очень интересно. Потыкай сам и всё станет еще более прозрачным. Давай пять, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a> <a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-57">

      <div class="body details">
3 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message110">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="03.10.2023 15:03:01 +07">
15:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:06, 393.1 KB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Привет коллеги. Как-то нашел на просторах github, интересную утилиту под названием <strong>Kill Port</strong>. Утилита написана bash.<br><br><em>Kill Port - инструмент командной строки для уничтожения процесса, запущенного на определенном порту.<br><br></em><strong>Ситуация.</strong> Запускаю я например какое-нибудь <strong>nodejs</strong> приложение или <strong>gunicorn</strong>, а оно начинает орать - а у тебя порт уже занят. Начинается беготня с выяснением, а кто это сделал?<br><br>Особенно актуально при локальной разработке, где-то в фоне что-то висит и радуется. Естественно никогда не можешь вспомнить, что нужно набрать в консоли, чтобы узнать, какой процесс занимает порт (конечно кроме 80 и 443, все и так знают что это nginx). <br><br>Лезешь в гугол, находишь в очередной раз <strong>lsof -i :3000</strong>, киляешь все это в надежде. И так далее.<br><br>Автор <strong>Kill Port</strong> видимо тоже исстрадался и изобрел свой осиновый кол. <strong>Суть утилиты простая</strong>, скармливаешь ей порт который нужно освободить, она находит все эти процессы и завершает их. На гифке это наглядно все представлено. Удобно!<br><br>Можно форкнуть проект и добавить туда известные процессы, тот же <strong>nginx</strong> и <strong>gunicorn</strong>, чтобы корректно их завершать, а не килить через -9 <strong>(SIGKILL).</strong> Хотя это лишнее. <strong>Kill Port</strong> работает из коробки, что еще нужно.<br><br><em>Есть нюанс при установке, там чет у него в инсталляторе напутано, поэтому просто клоним скрипт killport, кидаем в /usr/local/sbin с атрибутом +x.<br><br></em><strong>Для macos</strong>, утилита тоже работает, ставится через <strong>brew install killport.<br><br>Killport</strong><em> может не завершить процесс в случае определенных процессов работающие на уровне ядра, к примеру nfs / portmapper / wireguard. К ним не прикреплен соответствующий PID, но это крайние случаи. Для большинства сценариев, Killport успешно прикончит процесс.<br><br></em><a href = "stickers/AnimatedSticker.tgs">🐱</a><strong> Страница проекта на </strong><a href="https://github.com/BalliAsghar/killport">github<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-58">

      <div class="body details">
5 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message111">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.10.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Эх <s>суету</s> красоту навести охота! Привет. С помощью чего можно сделать <strong>красивые диалоговые боксы в скриптах</strong> и утилитах? Много всяких есть штук, но мне больше всего зашло использовать <strong>whiptail.<br><br>А зачем вообще красивые диалоговые окна в консоли?</strong> Можно же через <strong>read</strong> в <strong>bash</strong> всё прекрасно запрашивать. Да! Справедливо! Но  это скучно, гораздо интереснее получить какой-нибудь мало-мальски красивый и интуитивный интерфейс. <br><br>Например, когда ты устанавливаешь <strong>mysql</strong>, оно тебе выводить красивый инпут где нужно ввести <strong>root</strong> пароль. Либо устанавливаешь <strong>linux</strong> и нужно выбрать галочками, какие пакеты ты хочешь установить. Ну короче ты понял. Некий GUI.<br><br>Вот <strong>whiptail</strong> и позволяет сделать этот <strong>GUI</strong> с минимальными усилиями + интегрировать его в свои скрипты.<br><br>Устанавливается банально: <strong>apt/yum install whiptail,</strong> но обычно уже идет из коробки в дистрибутиве.<br><br>После установки, можно творить. Синтаксис очень простой:<br><br><pre>whiptail --yesno &quot;читаешь @bashdays?&quot; 10 50<br><br></pre>Откроется диалоговое окно с двумя кнопками <strong>yes/no</strong>, с текстом + высотой и длиной.<br><br>Помимо инпута <strong>yes/no</strong> имеется ряд других опций:<br><br><strong>msgbox</strong> - информативное окно с кнопкой OK<br><strong>infobox</strong> - херня какая-то, мигает и закрывается<br><strong>inputbox</strong> - поле для ввода текста<br><strong>passwordbox</strong> - поле для ввода пароля, скрыт звездочками<br><strong>textbox</strong> - выводит содержимое файла в окне<br><strong>menu</strong> - реализация меню<br><strong>checklist</strong> - чекбоксы<br><strong>radiolist</strong> - радиобатоны<br><strong>gauge</strong> - прогрессбар<br><br>В общем подойдет на все случаи жизни. Что интересно, можно реализовать неплохое меню, либо красиво отобразить на экране результат работы утилиты. Полет фантазии безграничный.<br><br>Теперь про то, <strong>как все это замешать в bash</strong> скрипты.<br><br>Логика простая. Если пользователь выбирает <strong>Yes</strong>, то <strong>whiptail</strong> вернет <strong>1</strong>. Если <strong>No</strong>, то вернет <strong>0.</strong> Если возникла ошибка, либо принудительное завершение, будет возвращен код <strong>-1.<br><br>Например:<br><br></strong><pre>if (whiptail --yesno &quot;Choose Yes or No&quot; 10 60)  then<br>     echo &quot;You chose Yes. Exit status was $?&quot;<br>else<br>     echo &quot;You chose No. Exit status was $?&quot;<br>fi<br><br></pre>Дефолные кнопки <strong>Yes/No</strong> можно зареврайтить с помощью опций <strong>--yes-button</strong> и <strong>--no-button.<br><br></strong><pre>whiptail --yes-button &quot;Fuck&quot; --no-button &quot;Yeee&quot; --yesno  &quot;What?&quot; 10 60<br><br></pre>Теперь вместо <strong>Yes/No</strong> наблюдаем <strong>Fuck/Yeee.<br><br></strong>Ну а <strong>как получать данные, которые ввели руками?</strong> А вот так:<br><br><pre>NAME=$(whiptail --inputbox &quot;What is your name?&quot; 10 60 3&gt;&amp;1 1&gt;&amp;2 2&gt;&amp;3)<br><br>exitstatus=$?<br>if [ $exitstatus = 0 ]; then<br>     echo &quot;Your name is:&quot; $NAME<br>else<br>     echo &quot;You chose Cancel&quot;<br>fi<br><br></pre>На экран выведется, то что, ты введешь в инпуте. Таким образом можно дальше строить диалоговые боксы и гонять <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">лысого</span></span> между ними введенные и выбранные переменные.<br><br><strong>Реализация меню:<br><br></strong><pre>OPTION=$(whiptail --menu &quot;Choose&quot; 15 60 2 &quot;1&quot; &quot;Linux&quot; &quot;2&quot; &quot;Windows&quot; 3&gt;&amp;1 1&gt;&amp;2 2&gt;&amp;3)<br> <br>exitstatus=$?<br>if [ $exitstatus = 0 ]; then<br>     echo &quot;Your chosen:&quot; $OPTION<br>else<br>     echo &quot;You chose Cancel.&quot;<br>fi<br><br></pre>В остальных случаях всё делается идентично. Но что такое <strong>3&gt;&amp;1 1&gt;&amp;2 2&gt;&amp;3?</strong> Это магия и скучная теория.<br><br>Перенаправление ввода-вывода <strong>stdin/stdout/stderr.</strong> Если коротко, без этого ничего не заработает. <strong>Скучная теория.</strong> В будущем расскажу про все эти перенаправления <strong>stdin/stdout/stderr</strong> на котиках. Пока просто делай как написано.<br><br>На закуску лови реализацию прогрессбара, тут хоть что-то происходит и движется:<br><br><pre>{<br>  for ((i = 0 ; i &lt;= 100 ; i+=20));  do<br>     sleep 1<br>     echo $i<br>  done<br>} | whiptail --gauge  &quot;Loading...&quot; 6 60 0<br><br></pre><strong>Основное рассмотрели. </strong>Можно брать и что-то уже клепать вменяемое. У <strong>whiptail</strong> есть аналог, называется <strong>dialog,</strong> посмотри, возможно он подойдет именно тебе, синтаксис похожий. <br><br><strong>💩</strong><strong> Картиночки собрал </strong><a href="https://telegra.ph/Whiptail-10-05">тут</a><strong>,</strong> чтобы визуально оценить масштабы всей этой суеты.<br><br>Если есть вопросы и предложения, задавай в комментариях. Давай, увидимся вечером, хорошего тебе дня!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
ʜ ᴅ
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message113">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.10.2023 19:32:04 +07">
19:32
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:31, 1.7 MB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Я всегда испытывал боль, когда нужно было вывести в консоли что-то цветное, закастомить так сказать серый результат своих скриптов. Все эти безумные конструкции с <strong>ANSI</strong> кодами постоянно вгоняли в депрессию.<br><br>Типа такого:<br><br><pre>echo -e &quot;\x1b[39;42mBashdays&quot;<br><br></pre>Но как мы знаем, всё уже придумано за нас, так получилось и в моем случае. Порыскав на просторах вселенной, я нашел несколько сервисов, которые позволяли мышкой натыкать нужную конфигурацию цветов и получить готовый <strong>ANSI</strong> код.<br><br>Самым топовым сервисом оказалась поделка <strong>ansicodes</strong> никому не известного разработчика. Собственно так и бывает, великие умы - славы не ищут.<br><br><strong>💩</strong><strong> Сервис доступен по </strong><a href="https://ansi.gabebanks.net/">ссылке<br></a><strong>🐱</strong><strong> Страница проекта на </strong><a href="https://github.com/Gbox4/ansicodes">github<br><br></a>Натыкиваешь мышкой нужную тебе конфигурацию цветов для консоли, по итогу получаешь готовый <strong>ANSI</strong> код, который вставляешь в свои скрипты и получаешь новогоднюю елку. Четко, быстро и без депрессий. Ну и можно на свой сервак воткнуть, там ничо сложного нет, обычный html + js.<br><br>Есть альтернатива <strong>🐱</strong><strong> </strong><a href="https://github.com/fidian/ansi">ansi</a><strong>,</strong> выполнена в роле отдельной утилиты, которую можно воткнуть в систему. Проект известный, но опять же в узких кругах. Но тут есть зависимости, а я не люблю зависимости, предпочитаю использовать коробочные инструменты.<br><br><em>Ну и всегда помни - если собираешься добавлять цвета в свой скрипт, всегда добавляй опцию —no-color, чтобы люди, анализирующие выходные данные скрипта, не испытывали к тебе ненависти.<br><br></em>Вот такие пироги!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em> </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-59">

      <div class="body details">
6 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message114">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.10.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Коллеги порой интересуются:</strong> Роман, а как ты слез с <strong>VSCode</strong> и пересел на <strong>vim</strong>? Есть какие-то мануалы и тренажеры?<br><br>А зачем тебе перелазить на vim? Чтобы что? Мануалов и тренажеров пруд пруди. Но всё это пустая трата времени. Самый эффективный способ пересеть на <strong>vim</strong>, это практика.<br><br>Просто открываешь <strong>vim</strong> и начинаешь писать в нем код. По ходу дела у тебя возникают вопросы:<br><br>1. А почему ничего не печатается?<br>2. А как сохранить то, что я напечатал?<br>3. А есть ли файловый браузер в сайдбаре?<br>4. А как какать?<br>5. А как искать нужную мне строчку?<br>6. А как отсюда выйти без перезагрузки процессора?<br>и т.п.<br><br>Такие вопросы возникают, потому что ты долгое время находился в зоне комфорта, а теперь эту зону комфорта отняли. Ну как отняли, ты сам так решил.<br><br><strong>Ну и как только возник какой-то вопрос - просто гуглишь.</strong> Вот и вся наука. Никакие тренажеры и толстенные книги, не сделают из тебя гуру и уверенного пользователя в этом замечательном редакторе.<br><br>Постепенно вопросов становится все меньше и меньше, твой <strong>vim</strong> обрастает плагинами и хоткеями, твои пальцы начинают заживать, в мозгу строятся новые нейронные связи. У некоторых даже отрастает шестой палец. Нервы спустя месяц приходят в норму. Всё меньше и меньше требуется мышка.<br><br>Да, при переходе на <strong>vim</strong> есть качели и побочки, но если с достоинством их преодолеть, то по итогу ты будешь вознагражден. Но это не точно.<br><br>Некоторый процент переходящих, приобретают хронический алкоголизм и депрессию. Так что будь аккуратен и готовься к таким переменам в своей жизни.<br><br><strong>На главный вопрос — А зачем я перелез на vim? Чтобы что?</strong> Увы, ты правильно ответить не сможешь. Возможно потешить своё ЭГО, повыебываться перед коллегами, отказаться от мыши, увеличить скорость работы. Всё спорно и относительно. Миграция на <strong>vim</strong> сопоставимо вопросу — а в чем смысл жизни?<br><br>Если ты с детства не приобщился к <strong>vim</strong>, подумай хорошо, а нужно ли тебе оно? В зависимости от твоего выбора, зависит твоя дальнейшая судьба. Остаться собой или познать нирвану.<br><br>Я просто люблю <strong>vim</strong>, в этом есть свой шарм. Когда я пишу код в <strong>vim</strong>, у меня повышается продуктивность, мне хочется находиться в этом редакторе и я получаю от этого своеобразный кайф.<br><br><strong>А за что ты любишь vim?<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-60">

      <div class="body details">
8 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message115">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.10.2023 15:07:01 +07">
15:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_11@08-10-2023_15-07-01.jpg">

         <img class="photo" src="photos/photo_11@08-10-2023_15-07-01_thumb.jpg" style="width: 260px; height: 173px"/>

        </a>

       </div>

       <div class="text">
В этот прекрасный осенний выходной, будем <strong>компилировать bash скрипт в бинарный файл.</strong> Да, да! И такое возможно.<br><br>Ну и зачем? Ну например я не хочу светить свой «прекрасный» код перед коллегами, либо выдаю себя за крутого разработчика который пишет на сисиписи.<br><br><strong>Встречаем Shc (Shell Script Compiler)<br><br>Shc</strong><em> принимает скрипт, который указан в командной строке и создает исходный код на C. Затем сгенерированный исходный код компилируется. Утилита shc сама по себе не является компилятором, она кодирует и шифрует сценарий оболочки.<br><br></em>Короче напоминает обычный криптор, для шифрования малварей от детекта антивирусами, алгоритмы схожие.<br><br>На выходе получаешь исходник на сях и готовый бинарник. Ставится все это дело так:<br><br><pre>apt/yum install build-essential gcc<br>apt/yum install shc <br><br></pre>Давай создадим бинарник:<br><br><pre>shc -f test.sh<br><br></pre>Рядом с файлом появятся еще 2 файла: <code>test.sh.x</code> и <code>test.sh.x.c</code> (первый это бинарник, второй исходник).<br><br>Проверяем:<br><br><pre>file test.sh.x<br><br>test.sh.x: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c265ebae7158a2c51461e890c15fdacb1cc81cb1, for GNU/Linux 3.2.0, stripped<br><br></pre>У shc есть множество ключей, к примеру ты можешь задать триальный период и бинарник будет превращаться в тыкву после определенной даты. Либо повысить уровень евристики и запутать реверс-инженера.<br><br><em>Минус тут один, это не golang и бинарник будет работать на схожих linux системах. Но это не страшно, пишешь в readme</em> <em>требования к запуску и снимаешь с себя ответственность.<br><br></em><strong>🐱</strong><strong> Страница проекта на </strong><a href="https://github.com/neurobin/shc">github<br><br></a>Вечером увидимся, далеко не убегай. Давай <a href = "video_files/sticker (56).webm">🤝</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message117">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.10.2023 20:02:42 +07">
20:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Щас крутая штука будет, фаер ин зе холл! <strong>Будем изолировать пользователя в linux</strong> и позволим ему запускать только разрешенные утилиты и команды. Короче говоря закейджим.<br><br>Для этого понадобится <strong>chroot</strong>, заходим под рутом и готовим подопытную папку <strong>env</strong>:<br><br><pre>cd / &amp;&amp; mkdir env<br>mkdir /env/{bin,lib,lib64}<br><br></pre><em>Chroot создает новую среду оболочки, что означает любые изменения, внесенные в эту среду, будут влиять только на файлы и каталоги в среде Chroot, а не на центральную нервную систему.<br><br></em>Папку создали, ок, теперь давай закинем в нее сам интерпретатор <strong>bash</strong>. После того, как пользователь зайдет на сервер по <strong>ssh</strong>, запустится <strong>bash</strong> в изолированной среде.<br><br>Чтобы определить, какие библиотеки использует утилита, воспользуемся утилитой <strong>ldd.<br><br></strong><pre>ldd /bin/bash<br><br></pre><em>Команда ldd осуществляет вывод списка разделяемых библиотек, используемых исполняемыми файлами или разделяемыми библиотеками.<br><br></em><strong>На экран вывелись библиотеки, которые использует bash<br><br></strong><pre>libtinfo.so.6 =&gt; /lib/libtinfo.so.6<br>libc.so.6 =&gt; /lib/libc.so.6<br>/lib64/ld-linux.so.2<br><br></pre>Их нужно закинуть в папку <strong>env</strong>, вот так:<br><br><pre>cp /usr/bin/bash /env/bin<br>cp /lib/libtinfo.so.6 /env/lib<br>cp /lib/libc.so.6 /env/lib<br>cp /lib64/ld-linux.so.2 /env/lib64<br><br></pre>Всё. <strong>Базовая изоляция готова.</strong> Для того чтобы после авторизации на сервере, пользователь попал в изолированную папку, делаем так:<br><br><strong>Добавляем в конфиг:</strong> <code>/etc/ssh/sshd_config<br><br></code><pre>Match User user<br>ChrootDirectory /env<br><br></pre>В первой строке, в конце указывает имя пользователя, которого будем изолировать, у меня в системе есть пользователь <strong>user</strong>, я его и указываю.<br><br>Далее дергаем <strong>systemctl restart sshd</strong> и пробуем залогиниться на сервер под пользователем:<br><br><pre>ssh user@bashdayz.ru<br><br></pre>Если все сделал правильно, то поздравляю, ты изолировал пользователя в системе и должен увидеть командную строку и что-то вроде <strong>-bash-5.1$. <br><br>Самый сок, в том, что никакие команды сейчас не работают, чтобы ты не вводил.</strong> Ты можешь лишь посмотреть версию <code>bash --version</code> или другие ее ключи.<br><br>Для того <strong>чтобы добавить</strong> в эту клетку <strong>другие утилиты, повторяешь трюк с ldd</strong>, копируешь бинарник и библиотеки.<br><br>Таким образом ты можешь делать кастрированный доступ по <strong>ssh</strong>, например для своих студентов либо для каких-то публичных квестов.<br><br><strong>Давай закрепим и добавим утилиту ls в нашу клетку:<br><br></strong><pre>ldd /usr/bin/ls<br><br>cp /usr/bin/ls /env/bin<br>cp /lib/libselinux.so.1 /env/lib/<br>cp /lib/libc.so.6 /env/lib/<br>cp /lib64/ld-linux.so.2 /env/lib64<br>cp /lib/libpcre2-8.so.0 /env/lib/libpcre2-8.so.0<br><br></pre>Смотрим зависимости через <strong>ldd</strong> и копируем их в нашу изолированную папку <strong>env.</strong> Теперь возвращаемся в терминал к пользователю <strong>user</strong> и пробуем запустить <strong>ls.</strong> <strong>Опа! Работает! Прекрасно!</strong> Попробуй теперь посмотреть файловую систему с помощью <strong>ls</strong> и убедись в наличии клетки.<br><br>Тема с <strong>chroot</strong> очень клевая, помимо того, что мы с тобой сейчас провернули, в chroot можно устанавливать полноценные дистрибутивы <strong>linux</strong> (возможно у тебя был сексуальный опыт с gentoo). Либо примонтировать <strong>proc/sys/dev/run</strong> с хостовой машины и сделать работу в <strong>chroot</strong> идеальной. Но это не совсем безопасно, тут уже тебе выбирать, удобство или параною.<br><br>А можно сделать 10 папок и 10 пользователей и в каждую папку воткнуть свой дистрибутив. Логинишься под <strong>user1</strong> и попадаешь в <strong>kali</strong>, логинишься под <strong>user2</strong> и попадаешь в <strong>centos</strong>. Ну ты понял.<br><br>Ладно, изучай, надеюсь было читабельно. Увидимся завтра!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a><strong> </strong><a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-61">

      <div class="body details">
9 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message119">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="09.10.2023 16:02:01 +07">
16:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_12@09-10-2023_16-02-01.jpg">

         <img class="photo" src="photos/photo_12@09-10-2023_16-02-01_thumb.jpg" style="width: 260px; height: 187px"/>

        </a>

       </div>

       <div class="text">
Работа с архивами и архиваторами, порой добавляет лишнюю головную боль. На уровне ДНК я помню как распаковать zip архив, но никак не могу отрастить нейроны, чтобы запомнить ключи и синтаксис распаковки tar, gz, 7z и т.п.<br><br>А запомнить не получается, по причине — я сталкиваюсь с архивами раз в пару недель или реже. Это как в программировании, если на какое-то время сделал паузу, то потом нужно заново проходить экспресс курс. Года два назад я очень хорошо знал JS и angular, сейчас я на них смотрю как баран на новые ворота.<br><br>Чтобы раз и навсегда избавиться от боли в работе с архивами я подсел на утилиту <strong>atool</strong>, которая чёрта лысого распакует/запакует/перепакует и не нужно заниматься лишней возней. Все просто.<br><br><em>Попросту говоря, atool это фронтэнд для консольных архиваторов, предоставляющий единый интерфейс для работы с ними.<br><br></em>Работает элементарно, скармливаем утилите архив, а она его распаковывает.<br><br><pre>atool -x shell.zip<br>atool -x shell.tar.gz<br>atool -x shell.7z<br>atool -x shell.rar<br><br></pre>Не нужно вспоминать никакие ключи и т.п. Указал ей <strong>-x</strong> или <strong>-X </strong>и погнали, а если еще и <strong>alias</strong> сделать, так вообще можно ничего не указывать. Клёва!<br><br>У <strong>atool</strong> есть много разных ключей, я использую ее в основном для распаковки. Но <strong>atool</strong> позволяет создавать архивы. Это же комбайн, как иначе.<br><br><strong>Давай создадим разные архивы:<br><br></strong><pre>atool -a -e -F .tar.gz shell<br>atool -a -e -F .zip shell<br>atool -a -e -F .7z shell<br>atool -a -e -F .rar shell<br><br></pre>Да, тут аж 3 ключа, но как я писал ранее, загоняй их в <strong>alias</strong> и можно потом вообще про это не париться.<br><br>По итогу получили 4 архива не вспоминая синтаксис архиваторов. Главное чтобы эти архиваторы были установлены в системе.<br><br>Развлекайся! Вечером наверное еще увидимся, посмотрим как по рабочей нагрузке будет. <strong>Хорошего тебе понедельника!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-62">

      <div class="body details">
10 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message120">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.10.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Я и подумать не мог, что для <strong>bash</strong> существует <strong>фреймворк для написания юнит тестов.</strong> Но недавно в одном проекте увидел и, честно говоря поплыл. Начал разбираться, что за странные конструкции в скриптах и по итогу вышел на <strong>фреймворк</strong> который называется <strong>bashunit.<br><br></strong>С одной стороны это удивительно и какое-то безумие, ну а с другой если в скрипте есть логика, почему бы не покрыть ее автотестами.<br><br><em>Bashunit это минималистичная библиотека тестирования Bash. Тестируйте свои bash-скрипты самым быстрым и простым способом.<br><br></em>Давай посмотрим как это работает и напишем первый тест:<br><br><strong>Устанавливаем:<br><br></strong><code>curl -s https://bashunit.typeddevs.com/install.sh | bash<br>ln ~/lib/bashunit /usr/local/sbin/bashunit<br><br></code>Все это добро залетит в папку: <strong>~/lib/bashunit.</strong> Ну и симлинк сделаем для удобства. Если посмотреть исходник <strong>bashunit,</strong> то увидим что, оно тоже написано на <strong>bash</strong>. <strong>Bash</strong> тестирует <strong>bash</strong>, красиво.<br><br><em>✅</em><em> Кто не знал, символ ~ означает домашнюю директорию текущего пользователя</em>. <em>А то сейчас начнешь искать, куда же эта тварь установилась.<br><br></em>Теперь создаем папку где будем складывать тесты: <strong>mkdir ~</strong><a href="" onclick="return ShowBotCommand(&quot;tests&quot;)">/tests</a>. В этой папке создаем файл <strong>first_test.sh</strong> и закидываем в него такой код:<br><br><code>#!/bin/bash<br><br>var=&quot;hello&quot;<br><br>function test_var_equals_hello() {<br>  assert_equals &quot;hello&quot; $var<br>}<br><br></code><strong>Запускаем:<br><br></strong><code>cd ~/<br>bashunit ./tests<br><br></code><strong>Получаем результат теста: All tests passed<br><br></strong><code>bashunit - 0.8.0<br>Running first_test.sh<br>✓ Passed: Var equals hello<br><br>Tests:      1 passed, 1 total<br>Assertions: 1 passed, 1 total<br>All tests passed<br>Time taken: 133 ms<br><br></code><strong>Assert_equals</strong> принимает 2 параметра, <strong>первый</strong> = ожидаемый результат, <strong>второй</strong> = фактический результат.<br><br><strong>Получается такое: </strong>Переменная <strong>var</strong> у меня равна <strong>«hello»,</strong> ожидаемый результат в тесте тоже <strong>«hello».</strong> Происходит сравнение и успешное завершение. Но если поменять значение <strong>var</strong> на что-то другое, то получим ошибку.<br><br><code>bashunit - 0.8.0<br>Running first_test.sh<br>✗ Failed: Var equals hello<br>    Expected &apos;hello&apos;<br>    but got &apos;fuck&apos;<br><br>Tests:      1 failed, 1 total<br>Assertions: 1 failed, 1 total<br>Some tests failed<br>Time taken: 128 ms<br><br></code>Помимо <strong>assert_equals,</strong> есть куча других методов проверки: assert_contains, assert_empty, assert_matches, assert_exit_code, assert_array_contains, assert_successful_code, assert_general_error, assert_command_not_found, assert_file_exists, assert_is_file и т.п.<br><br>Весь список можешь посмотреть в <a href="https://bashunit.typeddevs.com/assertions">официальной документации</a> с наглядными примерами.<br><br>Это лишь верхушка айсберга, того что умеет <strong>bashunit,</strong> под капотом есть куда разгуляться и замутить настоящие, профессиональные юнит тесты.<br><br>Если ты девопс и делаешь какое-нибудь тестовое задание связанное с написанием скриптов. Добавь автотесты и твои шансы получить оффер намного повысятся. Техдиры такое любят. Сразу видно, что человек следует бест-практикам и работает на результат, а не за деньги <a href = "video_files/sticker (57).webm">📺</a><br><br>Конечно ты вряд ли будешь покрывать тестами свои скрипты, но для общего разнообразия имей в виду, что в <strong>bash</strong> такое возможно. Изучай.<br><br><a href = "stickers/AnimatedSticker (7).tgs">💩</a> <strong>Официальный </strong><a href="https://bashunit.typeddevs.com/">сайт фреймворка<br></a><strong>🐱</strong><strong> Страница проекта на </strong><a href="https://github.com/TypedDevs/bashunit">github<br></a><strong>🐱</strong><strong> Старенькая альтернатива </strong><a href="https://github.com/kward/shunit2">shunit2<br><br></a>Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;qa&quot;)">#qa</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message122">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.10.2023 22:03:10 +07">
22:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Давай замутим ченить свое, простое и полезное. В этом посте изобретем <strong>шаринг файлов/папок с серверов прямо к себе в телеграм. </strong>Будем использовать <strong>bash</strong> и <strong>API</strong> телеграма.<br><br><strong>Задача: <br><br></strong>1. Нужно создать <strong>tar.gz</strong> архив файл/папку на сервере.<br>2. Закинуть этот архив себе в телеграм.<br>3. Почистить за собой.<br><br>Для начала сделаем телеграм бота, идем в <a href="https://t.me/BotFather">@BotFather</a> и получаем токен, вида: <code>11223344:HUYPIZDADJIGURGA</code>. Я назову бота <strong>bashdayz_bot.<br><br></strong>Подробности всей этой кухни описывать не буду, как ботов делать. Но там все просто, БотБатя тебе подскажет, приключений на 15 секунд, главное забрать токен. Если не разберешься, пиши в комментариях, поможем.<br><br><strong>Так, токен есть.</strong> Теперь нужно узнать <strong>ID</strong> своего пользователя в телеграм. Опять идем в бота, но в другого <a href="https://t.me/RawDataBot">@RawDataBot</a>, запускаем и смотрим поле: <code>&quot;chat&quot;: {&quot;id&quot;: 1234567890}.<br><br></code>Все это понадобится, чтобы перекинуть созданные архивы по API в телеграм. Дальше.<br><br><strong>Накидываем прототип скрипта shellshare<br><br></strong><pre>#!/bin/bash<br><br>chat_id=&quot;&quot;<br>bot_token=&quot;&quot;<br><br>stamp=$(date +%d%m%Y_%H%M%S)<br>filename=$1-$stamp.tar.gz<br><br>tar -czvf $filename &quot;$@&quot;<br><br>curl -F chat_id=&quot;${chat_id}&quot; -F parse_mode=&quot;HTML&quot; -F document=@&quot;$filename&quot; https://api.telegram.org/bot${bot_token}/sendDocument<br><br>rm $filename<br><br></pre>В переменную <strong>chat_id</strong> закидываешь <strong>id, </strong>который забрал у <strong>RawDataBot.</strong> А в переменную <strong>bot_token</strong> пишешь токен, который забрал у БотБати.<br><br><strong>Так, все готово. </strong>Теперь нужно запустить своего бота. Идем в телегу и ищем <a href="https://t.me/bashdayz_bot">@bashdayz_bot</a> которого создали в самом начале поста. Запускаем его. Ну вот и все, проверяем.<br><br><pre>./shellshare /var/log/nginx/<br>shellshare access.log error.log<br><br></pre>Создастся <strong>tar.gz</strong> архив, с названием одноименной папки/файла и прилетит тебе в бота <a href="https://t.me/bashdayz_bot">@bashdayz_bot</a> (но бот у тебя естественно будет с другим именем). После отправки, архив зачистится с сервера, чтобы место не занимать.<br><br>В скрипте использует нативное API телеграма через <strong>curl.</strong> А <strong>символ &quot;$@&quot;</strong> означает что скрипту можно передавать несколько папок/файлов, то есть массив. Но если в этом скрипте передать массив, то имя архива будет с именем первой папки, пусть тебя это не смущает. Если нужно будет, зафиксишь под свои нужды, мы делаем лишь прототип.<br><br>По желанию можешь сменить архиватор, впендюрить шифрование имен и установить пароль. Либо вообще через gpg криптануть.<br><br>Можно еще в <strong>curl</strong> передать <strong>caption,</strong> тогда в телеграм тебе придет архив с подписью, чтобы потом можно было ориентироваться что это такое.<br><br><pre>curl ... -F caption=&quot;${caption}&quot; ...<br><br></pre>В переменную <strong>caption</strong> передай текст, который нужен для подписи к архиву.<br><br><strong>Вот такая поделка получилась.</strong> Минус в том, что <strong>можно отправлять файлы размером не более 50 мегабайт.</strong> Но для всякой мелочи и конфигов подойдет, когда нужно быстро дернуть с сервака что-то себе и поделиться в корпоративном чатике.<br><br><em>Ну а если кто-то другой запустит твоего бота, то доступ к файлам не получит, потому что все файлы были отправлены на твой айдишник.<br><br>Тема с ботами интересная и много где применяется, у меня мониторинг на такое завязан да и куча еще всего. Даже если ты не делаешь бэкапы в телеграм, то знать как взаимодействовать с API телеги, необходимо. Однажды пригодится, когда начальник поставит задачу, а ты уже имеешь прокаченный скилл и понимание как это работает.</em> <em>Банально отправлять сообщения из gitlab при успехе/факапе отработки пайплайна.<br><br></em>Дорабатывай, изучай. Удачи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-63">

      <div class="body details">
11 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message124">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.10.2023 22:47:38 +07">
22:47
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_13@11-10-2023_22-47-38.jpg">

         <img class="photo" src="photos/photo_13@11-10-2023_22-47-38_thumb.jpg" style="width: 260px; height: 195px"/>

        </a>

       </div>

       <div class="text">
сегодня на изи, картинка...<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-64">

      <div class="body details">
13 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message125">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.10.2023 13:03:01 +07">
13:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_14@13-10-2023_13-03-01.jpg">

         <img class="photo" src="photos/photo_14@13-10-2023_13-03-01_thumb.jpg" style="width: 260px; height: 167px"/>

        </a>

       </div>

       <div class="text">
Привет! При работе с длинными консольными командами, возникает некий дискомфорт. Буквально вчера пришлось запускать docker контейнер без всяких композов и прочих обвязок. Команда получилась НУ 3.14здец длинной и не читаемой. <br><br>Почесал я свою лысую кабину и решил поискать тулзу, чтобы избавиться от этого дискомфорта. <strong>Ну и нашел неплохой форматер.<br><br></strong>Вставляешь в инпут свою монструозную команду и на выходе получаешь человеческое чтиво, разделенное символам переноса. Короче тулза ништяк все это форматирует и по итогу не надо самостоятельно бегать и тыкать 100500 раз кнопку Enter. Скопипастил себе в блокнотик и редактируешь в своё удовольствие.<br><br><em>Разработал и реализовал эту штуку, естественно ленивый девопс, у которого глаза выпали от консольных конструкций при работе с гугол облаком.<br><br></em><strong>💩</strong><strong> Сервис в </strong><a href="https://ray.run/tools/bash-command-formatter">онлайне<br></a><strong>🐱</strong><strong> Исходники на </strong><a href="https://gist.github.com/lucgagan/83698769dfc343e39b241fa6f1482b38">github<br><br></a><em>Можно на свой сервак поставить, если есть желание, там typescript.</em> <em>Но думаю тебе и онлайн сервиса за глаза хватит.<br><br></em><strong>Вечером поговорим наверное про хердок «HEREDOC» или про что-то другое.</strong> Увидимся! Лови котиков <a href = "video_files/sticker (58).webm">🥺</a> <a href = "video_files/sticker (55).webm">👍</a> <a href = "video_files/sticker (34).webm">🏃‍♂️</a><br><br>Ну и всем лёгкой рабочей пятницы и хороших предстоящих выходных!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message127">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.10.2023 19:36:41 +07">
19:36
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Так, давай сегодня обмусолим <strong>«HEREDOC».</strong> На вписках башников его гордо величают «Хердок».<br><br><strong>Что это такое?</strong> Ну смотри, допустим ты пишешь башник и оказываешься в ситуации, когда тебе нужно передать многострочный кусок текста, какой-нибудь команде типа <strong>cat, tee, ssh</strong> и т.п.<br><br>Вот с помощью «хердок» такое можно провернуть. Пока не очень понятно, давай разбираться на примерах.<br><br><pre>cat &lt;&lt; EOF<br>SUKA BLYA CURRENT DIR: $PWD<br>YOU ARE LOGGED IN ASS: $(whoami)<br>EOF<br><br></pre>В этом примере я передаю команде <strong>cat</strong> две строки текста, <strong>в первой</strong> есть переменная среды <strong>PWD,</strong> <strong>во второй</strong> команда <strong>whoami.<br><br>По итогу выхлоп будет такого плана:<br><br></strong><pre>SUKA BLYA CURRENT DIR: /home/user<br>YOU ARE LOGGED IN ASS: user<br><br></pre>Как видишь <strong>PWD</strong> и <strong>$(whoami)</strong> автоматически подставились. Ну и главная фича, что я не использовал для вывода команду <strong>echo.</strong> При другом раскладе код был бы таким:<br><br><pre>echo &quot;SUKA BLYA CURRENT DIR:&quot; $PWD<br>echo &quot;YOU ARE LOGGED IN ASS:&quot; $(whoami)<br><br></pre>Согласись, что с «хердоком» это выглядит более лаконичным. Не нужно писать <strong>100500 echo.</strong> Хердокаешь и меньше говнокода становится.<br><br><strong>Теперь давай выполним такой код:<br><br></strong><pre>cat &lt;&lt; &quot;EOF&quot;<br>SUKA BLYA CURRENT DIR: $PWD<br>YOU ARE LOGGED IN ASS: $(whoami)<br>EOF<br><br></pre>Заключив <strong>EOF</strong> в кавычки, я запретил заменять переменные, команды и спецсимволы.<br><br><strong>Короче на экран выведется такая шляпа:<br><br></strong><pre>SUKA BLYA CURRENT DIR: $PWD<br>YOU ARE LOGGED IN ASS: $(whoami)<br><br></pre>Видал да? <strong>PWD</strong> и <strong>$(whoami)</strong> не заменились, а остались в прежнем виде. <s>Заебись</s> Хорошо!<br><br><strong>Теперь давай рассмотрим такую конструкцию:<br><br></strong><pre>cat &lt;&lt;- EOF<br>    Hello<br>    Bitch<br>EOF<br><br></pre>В первой строке я добавил символ <strong>«-».<br><br></strong>Символ <strong>«-»</strong> приводит к игнорированию всех ведущих символов табуляции, что позволяет использовать отступы в синтаксисе «хердока». Пробелы не допускаются, только символ табуляции.<br><br>Перед <strong>«Привет»</strong> и <strong>«Пляж»</strong> я нажал <strong>TAB.</strong> Короче символ <strong>«-»</strong> позволяет делать отступы в коде с лидирующим Табом.<br><br><em>Не знаю, я этим минусом вообще не пользуюсь, мне хватает того, что есть в коробке.<br><br></em><strong>Теперь запускаем такое:<br><br></strong><pre>cat &lt;&lt; EOF &gt; output.txt<br>SLUNI DO POLU $PWD<br>HERANUKA PO ROYALU $(whoami)<br>EOF<br><br></pre><strong>А чо произошло?</strong> Хе… а весь выхлоп, который должен был вывестись на экран — сохранился в файл <strong>output.txt.</strong> Вот такая магия! Если файл не существует, то создастся новый.<br><br>Ну а если хочешь файл дополнить, то вместо <strong>«&gt;»</strong> используй двойные символы <strong>«&gt;&gt;»,</strong> но думаю ты это и так знаешь.<br><br>Передавать поток, можно не только в файл, но и в другие команды. Давай возьмем <strong>sed:<br><br></strong><pre>cat &lt;&lt;&apos;EOF&apos; | sed &apos;s/i/ee/g&apos;<br>Rich<br>Bitch<br>EOF<br><br></pre>По итогу получим, что все символы <strong>«i»</strong> заменятся на <strong>«ee».</strong> <strong>На экран выведется:<br><br></strong><pre>Reech<br>Beetch<br><br></pre>Конструкция напоминает франкенштейна, но если базу понимать, то все легко и просто. Но я думаю, что хорошо объясняю и тебе всё понятно. Если чо, спрашивай в комментах, раскидаем.<br><br><strong>Ну и как обычно на закуску</strong>, практическое применение этого самого «хердока»:<br><br><pre>ssh -T user@bashdayz.ru &lt;&lt; EOF<br>ls -la<br>date<br>apt update<br>uptime<br>cat /etc/issue<br>EOF<br><br></pre>Конектимся по <strong>ssh</strong> на сервер и выполняем пачкой задачи. Получается засылаем подготовленный пакет с командами и что-то делаем. Можно сделать скрипт базовой настройки сервера, чтобы ansible к примеру не городить. А можно циклом пройтись по списку серверов и избавиться от продакшена. <br><br><em>Если продакшен перестал падать, значит его больше нет</em>, <em>значит по ночам тебя перестанут будить.<br><br></em>На этой ноте, собственно всё. Больше тут и рассказать нечего.<br><br>Я редко пользуюсь «хердоком», но часто встречаю его в чужих скриптах. Тут скорее важен момент понимания, что происходит, а не момент использования. Вот теперь ты знаешь и сможешь читать более вдумчиво чужой говнокод.<br><br><strong>Давай! Еще раз хороших тебе выходных, увидимся!<br><br></strong><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-65">

      <div class="body details">
14 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message128">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="14.10.2023 18:41:11 +07">
18:41
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_15@14-10-2023_18-41-11.jpg">

         <img class="photo" src="photos/photo_15@14-10-2023_18-41-11_thumb.jpg" style="width: 260px; height: 135px"/>

        </a>

       </div>

       <div class="text">
Купил сегодня вентилятор для малины (raspberry pi) на 12v и только потом понял, что на борту платы есть лишь 3v и 5v. Короче собрал из старого и нового один рабочий, взлетело, хорошо быть инженером.<br><br>Ладно, <strong>давай про strace.</strong> Сегодня научимся смотреть что запускает программа и с какими параметрами она это запускает.<br><br>Возьмем для испытаний программу <strong>man</strong> и распотрошим её. <br><br><em>Команда man позволяет получить доступ к общей базе справки по команде, функции или программе. Обычно для просмотра справки программе надо передать название команды или другого объекта в системе.<br><br></em><strong>Екзекутим такую штуку:<br><br></strong><pre>strace -o logs -s1024 -fe execve man bash<br><br></pre>Ага, запустилось. Перед тобой открылась страница помощи <strong>bash.</strong> Что дальше. Дальше нажимаешь клавишу <strong>«q»,</strong> все это дело закрывается.<br><br>Давай <strong>теперь по ключам,</strong> а потом уже разберемся что произошло.<br><br><strong>s </strong>= длина выводимой строки<br><strong>f</strong> = отслеживаем дочерние процессы<br><strong>e</strong> = какой системный вызов отслеживаем<br><strong>o </strong>= куда сохраним результаты трассировки<br><br>Если не указывать ключ <strong>«o»,</strong> то результаты запишутся в стандартный поток STDERR.<br><br>И чо? А ничо, давай смотреть результаты, которые записались в файл с именем <strong>logs.<br><br></strong><pre>cat logs<br><br></pre>На экран вывелись результаты трассировки команды <strong>man. На картинке к этому посту, можешь посмотреть результат.<br><br></strong>Вот таким образом мы узнали какие утилиты и с какими аргументами запускается программа <strong>man</strong> для распаковки и форматирования <strong>man</strong> страниц.<br><br><em>То есть ты можешь отдебажить свою собственную программу, которая запускает какие-то внешние утилиты и т.п. И посмотреть что конкретно она запускает и с какими параметрами. Я так недавно php дебажил, который запускал ffmpeg из скрипта.<br><br></em>Ладно, пойду дальше пиво пить. Не отвлекаю, увидимся!<br><br><strong>UPD: </strong>Кстати чтобы сделать <strong>cat</strong> красивым, как на картинке, <a href="https://t.me/bashdays/75">читай это.<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br>—<br></em><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-66">

      <div class="body details">
17 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message129">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.10.2023 13:03:01 +07">
13:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, всем, ага. С утра разминочка, а ближе к обеду про более серьезные вещи поговорим.<br><br>Наверняка ты знаешь, что при нажатии сочетания клавиш <strong>CTRL+D</strong> завершится текущая интерактивная оболочка. То есть если ты сидишь на сервере по <strong>ssh</strong> и нажал <strong>CTRL+D,</strong> сессия прервется. ОК.<br><br>При нажатии такого сочетания, оболочка при чтении устройства терминала получит признак конца файла и <strong>завершится если строка пуста</strong>. Нюанс, если в командной строке набрать какие-то символы и нажать <strong>CTRL+D,</strong> то ничего не произойдет.<br><br>Как еще можно завершить сессию с командной оболочкой? Ну например установить значение переменной <strong>TMOUT</strong> больше нуля. <strong>Цифра будет означать секунды. <br><br></strong><pre># TMOUT=5<br><br></pre>Текущая сессия закроется через 5 секунд.<br><br>Следующий вариант это активировать параметр оболочки <strong>«t»</strong> с помощью команды <strong>set.<br><br></strong><pre>set -t <br><br></pre>Выбросило! НО! Оболочка прекратит свою работу, только после того, как завершится работа запущенных команд в текущий строке. Например:<br><br><pre>set -t ; read<br><br></pre>Выход произойдет, только <strong>после нажатия</strong> клавиши <strong>Enter.</strong> А в примере ниже:<br><br><pre>set -t ; read -t3<br><br></pre><strong>Выход</strong> будет произведен <strong>после нажатия Enter</strong> ИЛИ<strong> по прошествию 3х секунд.<br><br></strong>Так. Еще есть вариант с параметром <strong>«e».</strong> Указав его оболочка завершает работу после возникновения ошибки. Например:<br><br><pre>set -e ; false<br><br></pre><em>Команда false ничего не делает, но завершается всегда с ошибкой. Как правило, используется при написании bash скриптов.<br><br></em><strong>Более человеческий пример:<br><br></strong><pre>set -e ; Паравозблять<br><br></pre>И снова выкинуло. Потому что вернулась ошибка - <strong>Паравозблять: command not found.<br><br>Что еще упустили…</strong> Упустили команду <strong>exec.</strong> Подвешиваем на стандартный ввод устройство<strong> /dev/null. <br><br></strong><pre>exec &lt;/dev/null<br><br></pre>При чтении этого устройства оболочка получит признак конца файла и успешно завершится.<br><br>Ааа, еще же <strong>exit</strong> есть. Не буду его обижать, пусть тоже в этом посте присутствует.<br><br><strong>Ну и как обычно, на закуску.<br><br></strong><pre>stty eof $&apos;\t&apos;<br><br></pre><strong>Ёпта, что это?</strong> Это хак. После выполнения этой команды у тебя появится возможность закрыть текущую оболочку по нажатию на клавишу <strong>TAB.</strong> Ввод символа табуляции, посылает сигнал конца файла и оболочка прекращает свою работу.<br><br><em>stty (Set Teletype) - Эта команда управляет настройками терминала и позволяет пользователю вносить изменения в терминал и отображать его характеристики.<br><br></em>Всё, стоп! После обеда покажу, как с помощью <strong>strace</strong> можно инжектить в системные вызовы процессов для отладки некоторых ёбнутых случаев. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br>—<br></em><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message131">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.10.2023 16:14:03 +07">
16:14
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Большинство утилит/программ/скриптов и т.п. работают с временными файлами. Сначала они создают этот временный файл, пишут в него какие-то данные, а на выходе отдают готовый результат, будь то файл с выгрузкой либо что-то другое. А временный файл с которым производилась работа, естественно зачищается.<br><br>Наша <strong>задача на сегодня, перехватить</strong> этот <strong>временный файл, до того как он удалится.</strong> А для чего? Ситуации разные бывают.<br><br>Недавно я дебажил проблему с выгрузкой, которая годами работала, а потом сломалась, на выходе я получал пустой файл. Эту выгрузку делал как раз бинарник неизвестного происхождения. Отследить логику работы само собой не представлялось возможным.<br><br><strong>Этот случай я успешно отдебажил.</strong> Временный файл удалялся ДО того как стать файлом выгрузки. Почему? Потому что процесс удаления временного файла работал в отдельном потоке (thread) и удалял временный файл спустя 30 секунд.<br><br>А так как выгрузка с каждым годом становилась все больше, 30ти секунд стало мало. По итогу временный файл удалялся, а на выходе создавался пустой файл без каких либо данных. Естественно никакой обработки эксепшенов в бинарнике не было, вечный статус - завершено успешно! Файл же есть на выходе, значит успешно. Не поспоришь.<br><br><em>На такие ёбнутые случаи и нужен strace, чтобы хоть немного понять, что происходит.<br><br></em>Короче <strong>расчехляем нашу лабораторию</strong> и создаем скрипт. Бинарники мучить не будем, <strong>bash</strong> скрипта будет достаточно для понимания. <br><br><pre>#!/bin/bash<br><br>echo $UID &gt; /tmp/test.txt<br>unlink /tmp/test.txt<br><br></pre><em>UID обозначает идентификатор пользователя, то есть номер, назначенный каждому пользователю Linux.<br><br></em>1. Записываем во временный файл <strong>/tmp/test.txt</strong> этот самый UID.<br>2. Удаляем временный файл.<br><br><strong>Почему не rm а unlink?</strong> Потому что в моём случае это был именно <strong>unlink,</strong> который я нашел просматривая лог <strong>strace.</strong> Чем отличается <strong>unlink</strong> от <strong>rm,</strong> расскажу в следующих постах.<br><br>Так, подопытный скрипт есть. Запускаем так:<br><br><pre>strace -yfe inject=unlink:error=EACCES ./script.sh<br><br></pre>В этой конструкции мы говорим <strong>strace,</strong> чтобы проинжектил наш системный вызов <strong>unlink</strong> и передал ему насильно ошибку <strong>EACCES (Permission denied).<br><br></strong>В тот момент когда скрипт попытается удалить временный файл, наша инъекция не даст ему это сделать и завершит скрипт с ошибкой:<br><br><pre>[pid 677954] unlink(&quot;/tmp/test.txt&quot;) = -1 EACCES (Permission denied) (INJECTED)<br><br></pre>А сам временный файл останется на диске. Открываем его и смотрим, что же там внутри происходит.<br><br>По умолчанию инъекция будет сделана всем системным вызовам <strong>unlink,</strong> но есть возможность указать диапазон или конкретный индекс срабатывания. В <a href="https://t.me/bashdays/109">этом</a> посте можешь глянуть как узнать конкретный индекс (смотри строчку с when=4+).<br><br>В моем случае я увидел кусок своей выгрузки, которая резко прерывалась. Ну а дальше всё стало очевидным, что-то где-то не успевает. Включил таймер и нашел закономерность в 30 секунд, посмотрел дочерние процессы которые плодились и обнаружил активность этой зачищалки.<br><br>Отдал результаты дебага разработчикам, фиксить это конечно никто не стал, такой гемор никому не нужен. По итогу ребята с нуля переписали на golang и сразу чудным образом нашлась документация. Жиза.<br><br>Вот такие приключения порой случаются. Изучай. Хорошего дня!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-67">

      <div class="body details">
19 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message132">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="19.10.2023 14:24:42 +07">
14:24
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. <strong>Чем отличается команда rm от unlink?</strong> Давай смотреть. Обе эти команды умеют удалять, но в 99% ты используешь именно <strong>rm,</strong> потому что про <strong>unlink</strong> ты либо не слышал, либо тебе <strong>rm</strong> с головой хватает.<br><br>Есть ошибочное мнение, что <strong>unlink</strong> предназначен для удаления лишь  ссылок, нифига, оно вполне может удалять обычные файлы. А если углубиться, то весь процесс удаления в Linux, это удаление ссылок. <br><br><em>Как устроен процесс удаления файлов в linux, расскажу в следующих постах, сегодня у нас битва rm vs unlink.<br><br></em>У <strong>unlink</strong> есть всего лишь два ключа запуска <strong>help</strong> и <strong>version</strong>. Очень ограниченный инструмент, но чем инструмент проще, тем проще его синтаксис.<br><br><pre># unlink /tmp/hardlink<br># unlink /tmp/file<br><br></pre>Софтина очень молчаливая — как мужик. После удаления, она промолчит и ничего не выведет на экран. <br><br><em>Команда unlink использует системную команду unlink, в то время как команда rm использует системный вызов unlinkat. Оба системных вызова практически одинаковы.<br><br></em><strong>Unlink</strong> не умеет работать с <strong>wildcard</strong> и <strong>globbing</strong> шаблонами. Так же ты не сможешь с помощью нее удалить каталог. <br><br><strong>Короче одни минусы. А нахрена тогда она нужна?</strong> Ооо брат, сейчас расскажу. Запускаем команду и пытаемся насильно удалить файл которого нет в каталоге:<br><br><pre>rm -f test.txt<br><br></pre><strong>И получаем - НИЧЕГО.</strong> То есть <strong>rm -f</strong> не вернуло ошибку, что файл отсутствует. А если сделать так:<br><br><pre>unlink test.txt<br><br></pre>получаем ошибку:<br><br><pre>unlink: cannot unlink &apos;test.txt&apos;: No such file or directory<br><br></pre>То есть если мне нужно будет обработать результат выполнения команды <strong>rm -f,</strong> то я не буду достоверно знать, а существовал ли вообще файл. Ведь <strong>rm -f</strong> мне ничего не вернуло.<br><br>Короче с <strong>unlink</strong> можно гибче обрабатывать эксепшены в скриптах. А еще при использовании команды <strong>unlink</strong> отсутствует проверка безопасности. Она удалит файл, защищенный от записи. Хотя современная версия <strong>rm</strong> теперь тоже так умеет.<br><br><strong>Оффтоп. </strong>Ну а если хочешь, чтобы твой файл никто не смог удалить, включая root, делай так:<br><br><pre>chattr +i test.txt<br><br></pre><em>chattr позволяет устанавливать и отключать атрибуты файлов, на уровне файловой системы не зависимо от стандартных (чтение, запись, выполнение).<br><br></em>Ключ <strong>i -</strong> сделает файл неизменяемым. Чтобы снять с файла этот аттрибут, в команде которая выше, замени знак <strong>«+»</strong> на <strong>«-».<br><br>Подытожим.</strong> Для большинства повседневных задач конечно <strong>rm</strong> мастхев, но если ты пишешь софт для каких-то критичных систем, стоит не упускать из виду <strong>unlink.<br><br></strong>Увидимся вечером.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message134">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="19.10.2023 22:49:41 +07">
22:49
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_16@19-10-2023_22-49-41.jpg">

         <img class="photo" src="photos/photo_16@19-10-2023_22-49-41_thumb.jpg" style="width: 260px; height: 195px"/>

        </a>

       </div>

       <div class="text">
Писал писал я вам интересный пост на вечер, про очередные офигительные циркули <strong>gpt+terminal+bash,</strong> а потом понял, что эта сука денег через какое-то время хочет. Собственно, как и любая AI херовина, наивный. Короче заскамили мамонта. Форс мажор. Ну бывает… Раз не сложилось, давай так:<br><br><pre>shopt -s cdspell<br><br></pre><em>shopt — встроенная команда оболочки, управляет опциями. Изменяет значение внутренних конфигурационных параметров оболочки.<br><br></em>Далее делаем:<br><br><pre>cd /va<br>cd /otp<br>cd /Home<br><br></pre>Ха! Мы попадаем в каталог <strong>var/opt/home.</strong> Понял/а? Эта надстройка в терминале исправляет ошибки. Из коробки. Клёва! <br><br><strong>Призываем древнейшее зло</strong>:<br><br><pre>shopt -s autocd<br><br></pre><strong>Теперь вводим:<br><br></strong><pre>/etc/cron.d<br>~root<br>..<br>~-<br><br></pre>1. Переход в директорию <strong>/etc/cron.d<br></strong>2. Переход в хоумдир рута<br>3. Переход в папку на уровень выше<br>4. Переход в предыдущую директорию<br><br>Заметь что я не писал команду <strong>cd!</strong> Оно само…<br><br>Хз на сколько это вообще практично, но как видишь такое возможно. Изучай, может станешь фанатом этой фичи )<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-68">

      <div class="body details">
22 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message136">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="22.10.2023 17:24:59 +07">
17:24
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_17@22-10-2023_17-24-59.jpg">

         <img class="photo" src="photos/photo_17@22-10-2023_17-24-59_thumb.jpg" style="width: 260px; height: 138px"/>

        </a>

       </div>

       <div class="text">
Привет, о че нашел: <strong>пасхалка в текстовом редакторе nano.<br><br></strong>1. Запусти редактор <strong>nano<br></strong>2. Перейди на новую строку<br>3. Нажми <strong>CTRL+X,</strong> а затем<strong> Y<br></strong>4. Назови файл: <strong>zzy</strong> и нажми <strong>Enter<br><br></strong>Сочетание <strong>^X + Y + zzy,</strong> вероятно, является ссылкой на <strong>xyzzy,</strong> чит-код, первоначально использовавшийся в Colossal Cave Adventure.<br><br>Получается из <strong>nano</strong> нельзя будет сохранить файл с названием <strong>zzy.<br><br></strong><em>Там телега скоро запилит нормальное форматирование кода (в бете </em><a href="https://github.com/telegramdesktop/tdesktop/releases">4.10.4</a><em> уже работает). Наконец-то дождались, так что скоро все будет по красоте и без костылей. Я себе воткнул, уматно вообще!<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;трудовыебудни&quot;)">#трудовыебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-69">

      <div class="body details">
23 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message137">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.10.2023 13:10:24 +07">
13:10
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_18@23-10-2023_13-10-24.jpg">

         <img class="photo" src="photos/photo_18@23-10-2023_13-10-24_thumb.jpg" style="width: 260px; height: 122px"/>

        </a>

       </div>

       <div class="text">
Доброе утро господа и дамы… <strong>на картинки</strong> пока <strong>НЕ смотрим,</strong> все станет прозрачным чуть позже.<br><br>Создаем подопытный файл под рутом:<br><br><pre>echo &apos;some text&apos; &gt; test.txt<br><br></pre>За<strong>тар</strong>иваем его:<br><br><pre>tar -cf test.tar test.txt<br><br></pre>Теперь открываем в <strong>hexdump:<br><br></strong><pre>hexdump -C test.tar<br><br></pre><em>hexdump — инструмент который используется разработчиками и отладчиками приложений. Он может преобразовывать файлы и данные в приятный и читаемый формат.<br><br></em>Так, открыли. <strong>Смотри первую картинку</strong> к этому посту. Видишь <strong>root/root?</strong> Это имя владельца и имя группы файла. Так вот, при создании архива эти поля можно изменять. <br><br><strong>Давай изменим:<br><br></strong><pre>tar --owner=&apos;bash&apos; --group=&apos;days&apos; -cf test.tar test.txt<br><br></pre>Окей. Снова открываем в <strong>hexdump:<br><br></strong><pre>hexdump -C test.tar<br><br></pre><strong>Смотрим вторую картинку. </strong>На ней видим интересную ситуацию, пользователь изменился на <strong>bash,</strong> а группа на <strong>days.</strong> НО в <strong>системе у нас нет такого пользователя и группы.</strong> Хотя ожидаемый результат должен быть — <strong>user/group not found</strong> или что-то подобное.<br><br><pre>-rw-r--r-- bash/days 10 2023-10-23 05:09 test.txt<br><br></pre><strong>Баг или фича? </strong>Причем если рас<strong>тар</strong>ить такой файл (с ключом <strong>-p</strong> или без него), <strong>bash/days</strong> вернутся к <strong>root/root. <br><br></strong>А теперь создадим с <strong>user/user</strong> (этот пользователь и группа есть в системе).<br><br><pre>tar --owner=&apos;user&apos; --group=&apos;user&apos; -cf test.tar test.txt<br><br></pre>Распаковываем:<br><br><pre>tar -xf test.tar<br><br></pre>И видим ситуацию, что у файла <strong>test.txt</strong> пользователь и группа <strong>user/user.</strong> Великолепно! Вот такое интересное поведение.<br><br>Из <a href="https://www.gnu.org/software/tar/manual/html_node/Standard.html">документации</a> по тару по смещениям <strong>108</strong> и <strong>116</strong> находятся <strong>uid</strong> и <strong>gid.<br><br></strong><pre>char uid[8]; /* 108 */<br>char gid[8]; /* 116 */<br><br></pre>Давай посмотрим смещение 108:<br><br><pre>hexdump -Cs108 -n8 test.tar<br><br></pre>получаем:<br><br><pre>0000006c 30 30 30 31 37 35 30 00 |0001750.|00000074<br><br></pre>Конвертим 0001750 в <strong>uid:<br><br></strong><pre>echo $(( 8#1750 ))<br><br></pre>Опа, <strong>получили 1000,</strong> что соответствует пользователю <strong>user.</strong> А если этот трюк провернуть с <strong>bash/days</strong> то получим <strong>uid</strong> того пользователя, под которым тарили файл.<br><br>Короче как всегда везде есть свои нюансы и приколы, возможно обоснованные. Глубже копать не стал. Давай, увидимся вечерком!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message138">

      <div class="body">

       <div class="pull_right date details" title="23.10.2023 13:10:25 +07">
13:10
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_19@23-10-2023_13-10-25.jpg">

         <img class="photo" src="photos/photo_19@23-10-2023_13-10-25_thumb.jpg" style="width: 260px; height: 123px"/>

        </a>

       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message140">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.10.2023 20:03:01 +07">
20:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Часто люди бездумно засовывают в крон запуск долгоиграющих скриптов и потом ловят кучу багов.<br><br>К примеру некий скрипт запускается в кроне каждый час. В какой-то момент, время выполнения скрипта начинает составлять 70 и более минут. Соответственно следующий джоб через 60 минут запустит еще одну копию этого скрипта. И понеслась 3.14зда по кочкам.<br><br>Я ловил у ребят подобные перлы, когда сервер просто раком встает, а в фоне крутятся 100500 процессов, которые насилуют mysql как портовую шлюху, вдоль и поперек.<br><br>На такие случаи<strong> необходимо проверять запущен ли скрипт в данный момент.</strong> И если запущен, то при повторном запуске - ничего не делать.<br><br><strong>Как такое реализовать? </strong>В бест-практиках это реализуется через <strong>lock</strong> файлы. Для удобства работы с <strong>lock</strong> файлами, в linux есть коробочный вариант утилиты, которая называется <strong>flock.<br><br>flock</strong><em> — утилита, которая позволяет использовать лок-файл для предотвращения запуска копии процесса (вашего скрипта, крона или чего-то еще). Например, используя cron нужно быть уверенным, что предыдущий запуск вашего скрипта уже завершен.<br><br></em>Пишем обработчик:<br><br><pre>#!/bin/bash<br><br>lock=&quot;/tmp/bashdays.lock&quot;<br><br>[[ -f &quot;${lock}&quot; ]] || touch &quot;${lock}&quot;<br><br>(<br>    flock -n -o -x ${fd_lock} || { echo &apos;Nice try&apos; &gt;&amp;2; exit 0; }<br><br>    sleep 100<br><br>) {fd_lock}&lt;&quot;${lock}&quot;<br><br></pre><strong>Запускаем скрипт. </strong>Ничего полезного он не сделает, просто будет висеть 100 секунд. После того как ты запустил этот скрипт, в соседнем терминале попробуй запустить его же параллельно. В ответ ты получишь ожидаемое - <strong>Nice try.<br><br></strong>Как только скрипт завершит работу, ты сможешь запустить его повторно.<br><br>Сначала создается lock файл если его нет, а далее начинается магия с дескрипторами и логикой.<br><br><em>Вместо sleep можно вставить запуск функции типа main() где и будет основная логика скрипта. Либо вообще через source (или точку) заинклудить свой скрипт. То есть можно сделать универсальную штуку, чтобы в каждый скрипт не пихать flock.<br><br>Делаешь один обработчик и передаешь ему параметром путь до скрипта + путь до lock файла. А обработчик через source подгружает уже полезную нагрузку.<br><br></em>Моё решение возможно не самое изящное, но рабочее. Изучай. Слышал что такое можно провернуть каким-то образом через сокеты, но особо не вникал. Если в комментах поделишься, будет очень полезно. Спасибо!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
ʜ ᴅ
       </div>

      </div>

     </div>

     <div class="message service" id="message-70">

      <div class="body details">
25 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message141">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="25.10.2023 16:02:09 +07">
16:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_20@25-10-2023_16-02-09.jpg">

         <img class="photo" src="photos/photo_20@25-10-2023_16-02-09_thumb.jpg" style="width: 260px; height: 175px"/>

        </a>

       </div>

       <div class="text">
А у нас тут снежок выпал, хоть что-то новенькое. А то эти приготовления к чертовой пятнице (которая будет идти до конца года) совсем уже вымотали. Привет.<br><br>Набрел вчера на консольную игрулю, называется <strong>Rick &amp; Morty BASH Quest.<br><br></strong>Она как бы не совсем консольная, работает в браузере, но аутентичность сохранена.<br><br><em>Разработал эту пепяку преподаватель с дикого запада, чтобы потихоньку прививать своим безголовым студентам навыки работы в консоли.<br><br></em><strong>Сюжет прост</strong> - Саммер и Рик пропали! Нужно решить головоломки и найти их. Путешествуй по порталам, ищи подсказки, раскручивай истину.<br><br>Короче очередная залипалка для любителей подобных вещей. Да и визуально выглядит не как гавно, хоть под капотом и используется JQuery Terminal Library.<br><br><strong>Управление простое:<br><br>ls -</strong> осмотреться на местности<br><strong>cd -</strong> перемещение через порталы<br><strong>cat -</strong> читать подсказки<br><strong>pwd -</strong> если потерялся<br><strong>man man -</strong> справка<br><br><strong>🌐</strong><strong> Поиграть можешь</strong> <a href="http://adamsbashgame.pythonanywhere.com/">тут<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message142">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="25.10.2023 22:06:10 +07">
22:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Какой <strong>самый лучший способ</strong> на <strong>bash</strong> <strong>прочитать переменные из файла?</strong> Велосипедов я много повидал, но мастхев это конечно же закинуть все переменные в <strong>json</strong> файлик и без лишнего геморроя его использовать.<br><br>Создаем файл <strong>vars.json,</strong> закидываем в него переменные/константы или чо там у тебя в конфигах обычно содержится:<br><br><pre>{<br>    &quot;login&quot; : &quot;user&quot;,<br>    &quot;password&quot; : &quot;12345678&quot;<br>}<br><br></pre>А в главном скрипте, который все это будет читать делаем так:<br><br><pre>#!/bin/bash<br><br>config=&quot;vars.json&quot;<br><br>login=$(jq -r &apos;.login&apos; &lt; $config)<br>passwd=$(jq -r &apos;.password&apos; &lt; $config)<br><br>echo $login<br>echo $passwd<br><br></pre>Тут это - говорим в <strong>config</strong> как называется файл с переменными, а далее с помощью офигительной утилиты <strong>jq</strong> парсим конфиг без кучи говнокода и слёз.<br><br>Ключик <strong>-r</strong> означает, что выведется сырой текст (без кавычек и прочей нечисти). Попробуй убрать его и увидишь, что появятся кавычки, которые нам не нужны.<br><br><em>jq - это мощный инструмент, позволяющий читать, фильтровать и писать JSON в bash.<br><br></em><strong>jq</strong> вообще очень крутая тулза, но увы в коробке ее нет, придется ставить через менеджер пакетов. Но это мелочи.<br><br>Есть и другие способы работать с конфигами в <strong>bash,</strong> но как я выше сказал, <strong>json</strong> наше всё и мастхев. Изучай.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-71">

      <div class="body details">
26 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message143">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.10.2023 17:47:23 +07">
17:47
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ух ты сколько нас тут много стало. Привет, кого не видел. Давай поговорим про утилиту <strong>JC.</strong> Про нее почти никто не знает, значит  самое время познакомиться.<br><br><em>JC это JSON конвертер на основе встроенных парсеров.<br><br></em>Если коротко, то с помощью <strong>jc</strong> можно конвертировать выхлоп различных утилит в <strong>json</strong> формат, а потом уже по-человечески извлекать данные.<br><br>Например, я хочу получить <strong>json</strong> от выхлопа <strong>iptables.</strong> Запускаю:<br><br><pre>iptables -L | jc --iptables<br><br></pre>И по итогу получаю годноту:<br><br><pre>[{&quot;chain&quot;:&quot;INPUT&quot;,&quot;rules&quot;:[]},{&quot;chain&quot;:&quot;FORWARD&quot;,&quot;rules&quot;:[{&quot;target&quot;:&quot;DOCKER-USER&quot;,&quot;prot&quot;:&quot;all&quot;,&quot;opt&quot;:null,&quot;source&quot;:&quot;anywhere&quot;,&quot;destination&quot;:&quot;anywhere&quot;},{&quot;target&quot;:&quot;DOCKER&quot;,&quot;prot&quot;:&quot;all&quot;,&quot;opt&quot;:null,&quot;source&quot;:&quot;anywhere&quot;,&quot;destination&quot;:&quot;anywhere&quot;}..<br><br></pre>Ну красота же. <strong>JC</strong> ограничена парсерами, но из коробки там прям на богатом все (около 50ти). Crontab, csv, ls, fstab, date, ping и т.п. Выбираешь парсер под нужную тебе задачу и получаешь готовый к работе массив данных.<br><br>Выдирать данные само собой будет удобно через <strong>jq,</strong> вкидываем его в пайп, пишем какой ключ нужен и получаем желаемое.<br><br><strong>JC </strong>так же можно использовать как модуль в python, так что, тут не только у башников праздник.<br><br><a href = "stickers/AnimatedSticker (6).tgs">🐱</a> <strong>Страница проекта на </strong><a href="https://github.com/kellyjonbrazil/jc">github<br></a><strong>🟢</strong><strong> Установка:</strong> <code>apt/yum install jc<br><br></code>Лично я<strong> jc</strong> никогда не применял, но порой встречал в скриптах. Изучай, когда-нибудь обязательно пригодится.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-72">

      <div class="body details">
27 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message145">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.10.2023 00:03:03 +07">
00:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Спокойно! Завтра устроим выходной по постам, на сегодня это последнее чтиво, обещаю. Внезапная интеграция вылезла, нужно перекрывать.<strong> Давай на сон грядущий поговорим про интерпретатор.<br><br></strong>Все что работает на базе ядра linux, создание процесса происходит в два этапа. Процесс клонируется с помощью системных вызовов <strong>fork</strong> и <strong>clone.</strong> А копия процесса замещается кодом из указанного файла (exec). Детали пока опущу, речь про другое.<br><br>Ты всяко знаешь, что скрипт должен начинаться с символов <strong>#!.</strong> Эта штуковина называется <strong>SheBang.<br><br></strong>Е<em>сли дословно: SheBang = Она взрывает. Bang Bang, Feuer Frei! Как у Rammstein песенка, сразу фильм XXX на ум приходит. С лысым ЧСВ мужиком, а не про выгоревших чуваков позади дивана с одной миниатюрной мадмуазелью с дрочильного сайта.<br><br></em>В общем после <strong>#!</strong> нужно указать путь до интерпретатора, обычно мы с вами фигачим <strong>/bin/bash</strong> или питончик какой нибудь.<br><br>Данная конструкция будет использована системными вызовами семейства <strong>exec</strong> для запуска нужного интерпретатора, который в свою очередь исполнит картину маслом и запустит скрипт.<br><br>Если из командной строки запустить скрипт и системный вызов <strong>execve</strong> возвратит ошибку <strong>ENOEXEC<br><br>Процесс оболочки bash будет сам пытаться выполнить скрипт.<br><br>EXECVE()</strong><em> = выполняет программу, заданную параметром filename. Программа должна быть или двоичным исполняемым файлом, или скриптом, начинающимся со строки вида #!.<br><br>ENOEXEC = исполняемый файл в неизвестном формате, для другой архитектуры, или же встречены какие-то ошибки, препятствующие его выполнению.<br><br></em>В большинстве случаев <strong>ENOEXEC</strong> возвращается если первая строка не начинается с <strong>#!</strong> либо первая строка начинается с<strong> #!</strong> и в строке больше нет символов кроме пробелов и табуляций.<br><br><strong>Так вот, это запустится:<br><br></strong><pre>#!<br>echo &apos;Have a nice bashdays&apos;<br>exit<br><br></pre><strong>И это тоже запустится:<br><br></strong><pre># super comment<br>echo &apos;Have a nice bashdays&apos;<br>exit<br><br></pre><strong>Ну и это аналогично залетит в сакцесфул:<br><br></strong><pre>echo &apos;Have a nice bashdays&apos;<br>exit<br><br></pre>Так что не обязательно указывать нашу любимую конструкцию <strong>#!/bin/bash,</strong> интерпретатор тот еще жук и учитывает такие нюансы. <br><br>Если интересно поподробнее про это почитать, есть клевый <a href="https://www.in-ulm.de/~mascheck/various/shebang/">мануал</a> про всю эту суету с «ОнаВзрывает» или SheBang. Правда на английском, но с переводчиком вменяемо.<br><br>Исследуйте господа и дамы.<br><br>Всем котиков и доброй ночи <a href = "video_files/sticker (59).webm">🚶‍♀️</a> <a href = "video_files/sticker (54).webm">😎</a> <a href = "video_files/sticker (60).webm">☠️</a>  пойдука я дрыхнуть! А завтра наконец-то пятница и нет никаких ретроспектив и созвонов. Ура!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-73">

      <div class="body details">
29 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message146">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="29.10.2023 16:42:22 +07">
16:42
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ура, я кажется выспался и почти отошел от дегустации чачи. В прошлую пятницу, коллега попросил помочь ему накидать промпт, ну знаешь же там все эти <strong>PS1/PS2/PS3.</strong> Короче приглашение командной строки типа: root@bashdays:~#. <br><br>А мне сука так лень было этим заниматься, опять документацию поднимать, вспоминать все эти ключи и параметры. Короче Фууу! <br><br>Сижу думаю, как послать в пешее эротическое и не обидеть особо. Долго думать не пришлось. Все уже придумано за нас.<br><br>После минуты гугления, нашел несколько хороших генераторов этой самой фиготы. Тыкаешь мышкой по кнопочкам и получаешь готовый промпт.<br><br><em>Чёрт, как правильно промпт или промт? Промт по моему какой-то переводчик раньше такой был, в общем не суть.<br><br></em>Отдал найденные чудеса коллеге, за что получил респект и уважуху. Ну и делюсь находками с вами, мож тоже в хозяйстве пригодится.<br><br>- <a href="https://bash-prompt-generator.org/">Bash Prompt Generator<br></a>- <a href="https://promptgen.netlify.app/">Prompt Gen<br></a><a href="https://ezprompt.net/">- EZprompt<br><br></a><em>Там кстати телега обновление выпустила, всякие ништяки типа цитат, блоков кода и т.п. Буду теперь к постам это все применять. Не забудьте обновиться, чтобы у вас тут все красиво выглядело, а не как гавно.<br><br></em>Пойду дальше диван давить, да киношки смотреть. Наконец-то что-то похожее на выходной. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-74">

      <div class="body details">
30 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message147">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.10.2023 18:02:43 +07">
18:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вчера посмотрел спокойной ночи малыши и отрубился, каково было моё удивление, что в 6 утра не пришлось вставать и отвозить ребенка в школу. Каникулы же! Эхх… Ладно, а у нас бесконечные рабочие будни.<br><br>Сегодня обсудим интересную <strong>команду в bash,</strong> которая называется <strong>enable.</strong> Эта <strong>команда включает или отключает встроенные команды оболочки.</strong> Чтобы проще было понять эту шляпу, разберем на практике.<br><br><blockquote>Отключение встроенных команды позволяет выполнить дисковую команду, имеющую то же имя, что и встроенная команда оболочки, без указания полного пути, даже если оболочка ищет встроенные команды перед дисковыми командами.<br></blockquote><strong>Запускаем:<br><br></strong><pre>type test<br></pre> <br>И видим выхлоп: <strong>test is a shell builtin.</strong> То есть используется команда <strong>test</strong> встроенная в оболочку. А не та что лежит на пути в <strong>test: /usr/bin/test.</strong> А как нам воспользоваться дисковой версией этой утилиты? А вот так:<br><br><pre>enable -n test<br>type test <br><br></pre>И мы получаем уже такое: <strong>test is /usr/bin/test.</strong> Получается мы сделали некое переключение. И по факту используем разные версии <strong>test.<br><br></strong>Чтобы включить обратно встроенную команду <strong>test</strong> в оболочке, выполняем:<br><br><pre>enable test<br><br></pre>Так окей. <strong>Что еще можно с этим интересного сделать?</strong> А можно подгрузить расширения поставляемые с оболочкой. Некие плагины, экстеншены. Для этого эти экстеншены нужно установить (если у тебя их нет:<br><br><pre>apt/yum install bash-builtins<br><br></pre>Все это дело установится в папку <strong>/usr/lib/bash/.</strong> В ней будут всякие <strong>mkdir, rm, sleep</strong> и т.п. По сути это те же дисковые команды, только экстеншены для оболочки.<br><br>Для начала узнаем дисковую версию команды <strong>mkdir:<br><br></strong><pre>mkdir --version<br><br></pre>Ага, есть: <strong>mkdir (GNU coreutils) 8.32<br><br></strong>Теперь загружаем экстеншен в оболочку:<br><br><pre>enable -f /usr/lib/bash/mkdir mkdir<br>mkdir --version<br><br></pre>Хе! <strong>-bash: mkdir: --: invalid option<br><br></strong>Теперь запускаем:<br><br><pre>type mkdir<br><br></pre>И получаем: <strong>mkdir is a shell builtin,</strong> то есть теперь <strong>mkdir</strong> используется не системный (дисковый), а тот что подгружен в оболочку bash.<br><br><em>Например, ты снес все системные бинарники и у тебя есть только bash. Через подгрузку экстеншенов можно без проблем обслуживать свою операционную систему, даже если в системе пропали всякие mkdir и т.п.<br><br></em>Чтобы посмотреть что вообще подгружено в оболочку, воспользуйся командой:<br><br><pre>lsof +fg -p $$<br><br></pre>Получишь отчет по текущему процессу, что подгружено в данный момент в оболочку и используется.<br><br>С версии 4.4 в bash появилась переменная <strong>BASH_LOADABLES_PATH,</strong> с помощью нее ты можешь задать путь для поиска экстеншенов. Тогда при подгрузки этих модулей, не нужно будет использовать полные пути.<br><br><pre>BASH_LOADABLES_PATH=/usr/lib/bash/<br>enable -f sleep sleep<br><br></pre><strong>Для чего это может все пригодится?</strong> Да черт его знает. Например, можешь собрать <a href="https://t.me/bashdays/117">chroot</a> окружение и не добавлять дисковые утилиты, а подгрузить только необходимые модули для встроенной оболочки. <br><br>Ну либо в ситуации когда ты случайно снес бинарники и нужно как-то админить и восстанавливать систему. В общем тут всё рассчитано на полный полет твоей фантазии.<br><br>Развлекайся )<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message148">

      <div class="body">

       <div class="pull_right date details" title="30.10.2023 18:02:52 +07">
18:02
       </div>

       <div class="text">
Если у тебя коряво отображаются посты, либо вообще не отображаются (нарисован грустный <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">хуй</span></span> смайлик) - обнови клиента телеграм и все взлетит.<br><br><strong>Не пропустите </strong><a href="https://t.me/bashdays/147">новый</a><strong> пост, который выше 👆<br><br></strong><em>Форматирование постов еще отлажу, пока лезут баги особенно с форматированием кода, но думаю все скоро пофиксят.</em> <em>Еще бы картинки разрешили посреди текста пихать, было бы вообще пушка!</em>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message149">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="30.10.2023 22:17:16 +07">
22:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Короче с новой версией телеги просто 3.14здец какой-то, буду пока нативно через старый клиент посты фигачить, без всех этих свистоперделок. Если <a href="https://t.me/bashdays/147">статью</a> про циркули не увидел, я позаботился о тебе и закинул ее в телеграф. Читай нативку прям из клиента, не должно всей это шляпы больше вылазить. Всем спасибо ребята за фидбеки!<br><br><a href="https://telegra.ph/Enable-in-da-Bash-10-30">https://telegra.ph/Enable-in-da-Bash-10-30</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-75">

      <div class="body details">
31 October 2023
      </div>

     </div>

     <div class="message default clearfix" id="message150">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="31.10.2023 13:03:06 +07">
13:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Подсмотрел тут у товарища интересную идею с итогами по постам за прошлый месяц. Типа ТОП лист самого интересного, что прям со свистом залетело в умы. Попробую и я такое провернуть. Поехали!<br><br><strong>Больше всего просмотров:<br><br></strong>- <a href="https://t.me/bashdays/145">Про SheBang и интерпретатор</a> (7350)<br>- <a href="https://t.me/bashdays/122">Шаринг файлов с серверов в телеграм</a> (6834)<br>- <a href="https://t.me/bashdays/143">Утилита JC</a> (6545)<br>- <a href="https://t.me/bashdays/125">Форматер длинных строк</a> (6469)<br>- <a href="https://t.me/bashdays/134">Приколы с утилитой shopt</a> (6379)<br>- <a href="https://t.me/bashdays/127">Потрошим HereDoc</a> (6300)<br>- <a href="https://t.me/bashdays/119">Комбайн для архиваторов</a> (6239)<br>- <a href="https://t.me/bashdays/142">Лучший способ читать переменные из файла</a> (6186)<br>- <a href="https://t.me/bashdays/114">Как перелезть на VIM и не помереть</a> (6089)<br><br><strong>Больше всего пересылок:<br><br></strong>- <a href="https://t.me/bashdays/117">Изолируем пользователя в chroot</a> (177)<br>- <a href="https://t.me/bashdays/115">Компилируем bash скрипт в бинарный файл</a> (136)<br>- <a href="https://t.me/bashdays/111">Делаем красивые диалоговые окна</a> (135)<br>- <a href="https://t.me/bashdays/141">Игруля Rick &amp; Morty Quest</a> (132)<br>- <a href="https://t.me/bashdays/140">Про flock и долгоиграющие скрипты</a> (131)<br>- <a href="https://t.me/bashdays/120">Фреймворк для тестирования bash скриптов</a> (120)<br>- <a href="https://t.me/bashdays/110">Уничтожаем процесс через порт с помощью Kill Port</a> (113)<br><br><strong>Больше всего комментариев и лайков:<br><br></strong>- <a href="https://t.me/bashdays/128">Strace или что запускает программа<br></a>- <a href="https://t.me/bashdays/129">Про CTRL+D и завершение сессий<br></a>- <a href="https://t.me/bashdays/146">Bash Prompt Generator<br></a>- <a href="https://t.me/bashdays/132">Чем отличается rm от unlink<br><br></a>Ну и не забываем, что есть навигация по тэгам (<a href="https://t.me/bashdays/15">в закрепленном сообщении</a>). Да, очень хорошо выстреливает рубрика <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a>. Надо наверное за прошлые месяцы тоже будет такую табличку сделать.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;итогимесяца&quot;)">#итогимесяца</a><em> 10/23<br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message152">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="31.10.2023 19:03:01 +07">
19:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_21@31-10-2023_19-03-01.jpg">

         <img class="photo" src="photos/photo_21@31-10-2023_19-03-01_thumb.jpg" style="width: 260px; height: 149px"/>

        </a>

       </div>

       <div class="text">
<strong>О чо у меня есть, офигительная шпаргалина!<br><br></strong><em>n.e. в колонке означает not existing (не существует)<br><br></em><strong>Давай разберем:<br><br></strong><pre>command &gt; file.txt<br><br></pre>Поток вывода перенаправлен в файл, в терминале его не видно. Если файл существует, он будет перезаписан.<br><br><pre>command &gt;&gt; file.txt<br><br></pre>Поток вывода перенаправлен в файл, в терминале его не видно. Если файл существует, то новые данные добавятся в конец файла.<br><br><pre>command 2&gt; file.txt<br><br></pre>Поток ошибок перенаправлен в файл, в терминале его видно. Если файл существует, он будет перезаписан.<br><br><pre>command 2&gt;&gt; file.txt<br><br></pre>Поток ошибок перенаправлен в файл, в терминале его не видно. Если файл существует, то новые данные будут добавлены в конец файла.<br><br><pre>command &amp;&gt; file.txt<br><br></pre>Поток вывода и поток ошибок перенаправлены в файл, в терминале их не видно. Если файл уже существует, то он будет перезаписан.<br><br><pre>command &amp;&gt;&gt; file.txt<br><br></pre>Поток вывода и поток ошибок перенаправлены в файл, в терминале их не видно. Если файл уже существует, то новые данные будут добавлены в конец файла.<br><br><pre>command | tee file.txt<br><br></pre>Поток вывода скопирован в файл, он виден в терминале. Если файл уже существует, то он перезапишется.<br><br><em>Команда tee в Linux считывает стандартный ввод и записывает его одновременно в стандартный вывод и в один или несколько подготовленных файлов.<br><br></em><pre>command | tee -a file.txt<br><br></pre>Поток вывода скопирован в файл, он виден в терминале. Если файл уже существует, то новые данные будут добавлены в конец файла.<br><br><pre>(*)<br><br></pre>В Bash нет сокращенного синтаксиса, позволяющего передавать только StdErr второй команде, что было бы необходимо в данном случае в сочетании с tee для завершения операции. <br><br><pre>command |&amp; tee file.txt<br><br></pre>В файл скопированы потоки вывода и ошибки, они видны в терминале. Если файл уже существует, то он перезапишется.<br><br><pre>command |&amp; tee -a file<br><br></pre>Потоки вывода и ошибки скопированы в файл, в терминале их видно. Если файл уже существует, то новые данные будут добавлены в конец файла.<br><br><em>Вот такие пироги. Подробнее стандартные потоки разберем в следующих постах, многие их не понимают. Изучай.<br><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;sheets&quot;)">#sheets</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-76">

      <div class="body details">
1 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message153">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.11.2023 12:13:59 +07">
12:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем привет и доброе утро. Ребята вчера попросили анонсировать <a href="https://t.me/bashday">наш чатик.</a> Собственно анонсирую — у нас есть чатик. <strong>В нём можешь смело задавать свои вопросы</strong> или рассказать всем про своё рабочее место, ну или как ты ушатал продакшен.<br><br>Ссаными тряпками никто не прогонит, <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">(могут конечно нахуй послать, но это детали)</span></span> все в адеквате. Вступление по заявкам, модерирую вручную чтобы автоботы поменьше щемились.<br><br><em>Ну а если устал от всех этих технических штук, велком в наши юморные айти каналы </em><a href="https://t.me/+EgCNbg8PaltmNmZi">«Псина»</a><em> и </em><a href="https://t.me/+bBrOqidGNrZkNDg6">«Гарден».</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message155">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.11.2023 17:26:53 +07">
17:26
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_22@01-11-2023_17-26-53.jpg">

         <img class="photo" src="photos/photo_22@01-11-2023_17-26-53_thumb.jpg" style="width: 260px; height: 211px"/>

        </a>

       </div>

       <div class="text">
Пока я готовлю разжеванный пост про стандартные потоки ввода-вывода, закину тебе еще одну игрулю для изучения оболочки через геймификацию.<br><br>Автору изобретения, капец как надоело бодаться с первокурсниками, у которых вместо головы - палено. Вот он и изобрел этот тренажер, чтобы эти тупни сами во всем разбирались проходя увлекательные миссии.<br><br><strong>Называется эта поделка GameShell.<br><br></strong><em>Ну логично, в наше время большинство вайтишных курсов так и устроены. Сам все изучаешь через гугол попивая крепкие напитки, чтобы не сойти с ума.<br><br></em>Русского языка по понятным причинам в этот тренажер не завезли, но будет лишний повод подтянуть английский/французский/эсперанто.<br><br><strong>GameShell</strong> запустится на любой операционке Linux/macOS.<br><br><strong>Устанавливать так:<br><br></strong><pre>sudo apt install gettext man-db procps psmisc nano tree bsdmainutils x11-apps wget<br><br>$ wget https://github.com/phyver/GameShell/releases/download/latest/gameshell.sh<br>$ bash gameshell.sh<br><br></pre>Вот и все. <strong>Цель игры:</strong> Выполнять миссии, продвигаться вперед и сохранить рассудок. Если соберешь все яйца, в конце покажут мультик, но это не точно.<br><br><strong>🐱</strong><strong> Страница проекта на </strong><a href="https://github.com/phyver/GameShell">github<br><br></a><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-77">

      <div class="body details">
3 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message156">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="03.11.2023 17:06:42 +07">
17:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Я часто использую <strong>set -xve</strong> для отладки <strong>bash</strong> скриптов. Вообще это мастхев фича именно на момент, когда ты что-то создаешь. Ведь не всегда логика может работать правильно (в моих случаях так и есть), а с <strong>set -xve,</strong> ты вовремя можешь увидеть все значения переменных и т.п. не используя мусорные конструкции в своих поделках типа <strong>echo «Error in function xxx».<br><br></strong>Конструкцию с <strong>set</strong> я обычно вставляю в <strong>shebang</strong> либо после, отдельным сетом:<br><br><pre>#!/bin/bash -xve<br><br>set -xve<br><br>&lt;script body&gt;<br><br></pre><strong>Ключики команды set:<br><br>x =</strong><em> Выводим команды и их аргументы по мере их выполнения.<br>v = Выводить строки ввода командной строки по мере их считывания.<br>e = Немедленный выход, если команда завершается с ненулевым статусом.<br><br></em>Окей. Как-то дебажил один большой и сложный скрипт на овердофига строк. В какой-то момент скрипт завершался с ошибкой. В режиме отладки <strong>set -xve</strong> я видел, где он упал. <strong>Но мне хотелось знать — а на какой строке это произошло?</strong> Номера строк увы не выводятся, а по поиску и визуально искать - ну такое себе.<br><br>Эхх, одна задача превратилась в другую. В общем решил разок упороться и проресерчить этот вопрос, на будущее так сказать. <strong>По итогу получилось так:<br><br>Изменяем PS4</strong> и добавляем вывод номера строки во включенный дебаг режим:<br><br><pre>#!/bin/bash -xve<br><br>PS4=&apos;+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }&apos;<br><br>bar=10<br>echo ${bar}<br>echo $((6 + 6))<br><br></pre>После выполнения скрипта, <strong>получаем нумерацию строк:<br><br></strong><pre>bar=10<br>+(./script.sh:6): foo=10<br>echo ${bar}<br>+(./script.sh:7): echo 10<br>10<br>echo $((6 + 6))<br>+(./script.sh:8): echo 12<br>4<br><br></pre>Теперь если скрипт где-то вылетает с плохим статусом (либо происходит что-то другое), всегда можно узнать в какой строке это приключилось, не бегая по огромному куску кода.<br><br>Ну а чтобы <strong>добавить визуального оргазма,</strong> экспортируем <strong>PS4</strong> так:<br><br><pre>PS4=&apos;\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }&apos;<br><br></pre><strong>Происходит подкрашивание запускаемых строчек. <br><br></strong><em>С помощью PS4 мы можем отладить shell-скрипт, задав при его выполнении set -x, что позволяет выводить каждую команду, а затем ее результаты. Перед каждой командой ставится знак +, эту строку подсказки &quot;+&quot; можно изменить, определив переменную PS4.<br><br></em>Берите на вооружение. Хорошего дебага и с пятницей. Берегите себя!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-78">

      <div class="body details">
4 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message157">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="04.11.2023 15:04:01 +07">
15:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Доброе утро и привет!<br><br>В этот прекрасный выходной я научу тебя <strong>как узнать имя функции из самой функции.<br><br></strong><pre>#!/bin/bash<br><br>deploy() {<br>  # здесь хочу получить &quot;deploy&quot;<br>}<br><br></pre>Для получения имени функции из самой функции, можно воспользоваться переменной <strong>${FUNCNAME[*]}.<br><br></strong>Элемент с индексом <strong>0</strong> это имя любой выполняемой функции в данный момент. Ну а тот что имеет самый большой индекс, в моем случае это <strong>1</strong> (так как функция у меня одна) будет называться <strong>main.<br><br></strong><pre>deploy() {<br>    echo ${FUNCNAME[0]}<br>}<br><br></pre><strong>Выведет название функции: </strong>deploy<br><br>Переменная <strong>FUNCNAME</strong> существует только во время выполнения скрипта. Если самостоятельно задать переменную <strong>FUNCNAME,</strong> это ничего не даст и все равно выведется эталонное имя функции.<br><br>При обращении к массиву без индекса, будет возвращен первый элемент массива текущий функции. Но так же будет содержать все остальные функции в стеке вызова.<br><br><strong>Например:<br><br></strong><pre>exp1() {<br>    echo ${FUNCNAME}<br>}<br><br>exp2() {<br>    echo ${FUNCNAME[*]}<br>}<br><br></pre>Первая функция выведет: <strong>exp1,</strong> а вторая выведет весь массив функции: <strong>exp2 main.<br><br></strong>Вообще не обязательно указывать индекс, оно будет корректно работать и так. Это больше как кодстайл. Как в конце строки ставишь точку с запятой, которая не влияет на функционал программы и вообще никак не интерпретируется.<br><br>Ну а в <strong>zsh</strong> это штука называется <strong>funcstack,</strong> это тот же массив всех функций скрипта.<br><br><pre>deploy() {<br>   echo $funcstack[1]<br>}<br><br></pre><em>Еще переменная FUNCNAME используется с BASH_LINENO и BASH_SOURCE, но про это уже можешь глянуть в </em><a href="https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html">официальной документации</a><em>, как там вся эта магия происходит.<br><br></em><strong>BASH_SOURCE</strong> - переменная, содержит путь к исходному файлу оболочки, полезна при отладке и анализе ошибок.<br><br><strong>BASH_LINENO</strong> - переменная, содержит номер строки на которой произошла ошибка в текущем скрипте.<br><br>Вечером подвезу еще ништяков. Пойду маркировать интеграции, разгребать бухгалтерию, да готовить закупы на следующую неделю. Еще единомышленников немного сюда приведем. Давай пять, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message159">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="04.11.2023 19:17:29 +07">
19:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сейчас за кружкой чая, кореш задал вопрос - Ромыч, а расскажи мне, что означает <strong>2&gt;&amp;1?</strong> Хм… Нашел время, а так хорошо сидели.<br><br>Расскажу и тебе, понятно дело, что это магия со стандартными потоками вывода.  <br><br>Как мы знаем, потоки вывода имеют файловые дескрипторы:<br><br><strong>stdout = 1</strong> (общий поток вывода)<br><strong>stderr = 2</strong> (поток с ошибками)<br><br><strong>Получается (2&gt;&amp;1) = stderr &gt; stdout.</strong> То есть направляем поток с ошибками, в стандартный поток вывода. Ошибки будут выводиться на экран в терминале.<br><br><strong>Логичным было бы сделать конструкцию: 2&gt;1.</strong> Но увы, эта схема отработает другую логическую операцию. Поток с ошибками <strong>stderr</strong> будет писать все данные в файл, у которого название будет <strong>1.<br><br></strong>Вот для этого и требуется указать символ <strong>&amp;</strong> (амперсанд) перед <strong>stdout.</strong> Это будет интерпретировано как файловый дескриптор, а не обычный файл.<br><br><strong>А почему тогда не &amp;2&gt;&amp;1. Логично же?</strong> Но нет! Символ <strong>&amp;</strong> интерпретируется как файловый дескриптор только в контексте перенаправления.<br><br>Операция <strong>command &amp;2&gt;&amp;1</strong> анализируется так: <strong>command &amp; 2&gt;&amp;1.</strong> То есть  команда <strong>command</strong> будет выполнятся в фоновом режиме. А затем начнет выполнятся команда <strong>2 </strong>с перенаправлением на стандартный вывод <strong>stdout.<br><br></strong>Вот такие дела.<strong> А еще есть альтернатива с оператором |&amp;.<br><br>|&amp;</strong> это сокращенный вариант от <strong>2&gt;&amp;1 |<br><br>Пример:<br><br></strong><pre>script.sh |&amp; tee -a /var/log/script.log<br><br></pre>Все что <code>script.sh</code> выведет в потоки <strong>stdout</strong> и <strong>stderr</strong>, будет перенаправлено в файл <strong>script.log.<br><br></strong>В <a href="https://www.gnu.org/software/bash/manual/bash.html#Pipelines">официальной документации</a> этот момент хорошо расписан, но я расписал тебе еще проще.<br><br><strong>Как говорится — мы из рощи, мы попроще! </strong>Всё, не смею тебя больше отвлекать, спасибо за внимание. Увидимся скорее всего в понедельник или вторник. Если чо пиши в <a href="https://t.me/bashday">чатик,</a> мы там завсегда тебе рады!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-79">

      <div class="body details">
7 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message160">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.11.2023 17:02:33 +07">
17:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, друзья! Есть у меня какой-то долгоиграющий скрипт, который я по дурости запустил в терминале, без <strong>nohup</strong> и применения <strong>screen.</strong> Ждать завершения скрипта не вариант, но и завершать его принудительно нельзя. Как быть? Сейчас покажу, поехали.<br><br>Сделаем подопытный образец, который в цикле будет писать в файл числа от 1 до 10000, чтобы визуально понимать что происходит. Ну и паузу впендюрим 2 секунды, для чистоты эксперимента.<br><br><pre>#!/bin/bash<br><br>for i in {1..10000}<br>do<br> echo $i &gt;&gt; /tmp/log.txt<br> sleep 2<br>done<br><br></pre>Запускаем, ага. Теперь открываем второй терминал и пишем:<br><br><pre>tail -f /tmp/log.txt<br><br></pre>Видим как файл <strong>log.txt</strong> постепенно наполняется циферками. <br><br>Всё прекрасно. Что нужно сделать дальше. А дальше жми сочетание клавиш <strong>ctrl+z</strong> в первом терминале, где ты запустил скрипт.<br><br><em>Комбинация клавиш Ctrl + Z посылает процессу сигнал, который приказывает ему остановиться. Это значит, что процесс остается в системе, но как бы замораживается.</em><br><br><strong>Ловим такое:<br><br></strong><pre>[1]+ Stopped ./script.sh<br><br></pre>Видим что скрипт остановил свою работу. А во втором терминале с <strong>tail,</strong> цифры перестали заполнять файл <strong>log.txt.</strong> <strong>Ключевое слово - остановил, но не прекратил.</strong> Окей, мы на верном пути.<br><br>А теперь в первом терминале запускай команду <strong>bg</strong>, в ответ ты увидишь такое:<br><br><pre>[1] + ./script.sh &amp; <br><br></pre>Видишь в конце закорючку <strong>&amp;,</strong> наталкивает на мысли? <a href = "stickers/sticker (19).webp">🤒</a><br><br><em>Команда bg предназначена для возобновления исполнения остановленной задачи в фоновом режиме в командных оболочках.<br><br></em>Скрипт продолжил работу в фоне, с того момента где ты его приостановил. Идем во второй терминал с <strong>tail</strong> и видим, что цифры продолжили заполнять файл.<br><br>Круто! Но это пока еще не все, если закрыть первый терминал, скрипт прекратит свою работу, <strong>нужно его как-то отвязать от текущей сессии</strong> и демонизировать. <br><strong><br>Запускаем финалочку:</strong><br><br><pre>disown %1</pre><br><br><em>Команда disown блокирует отправку системного сигнала SIGHUP с помощью командной оболочки и исполняющемуся в фоновом режиме процессу при завершении работы командной оболочки. </em><br><br>Теперь в первом терминале пишем <strong>exit</strong> либо просто закрываем его нахрен. <strong>Ха! А во втором терминале работа скрипта продолжается. Магия!</strong><br><em><br></em>Вот таким образом ты можешь легко отвязать уже запущенный скрипт от терминальной сессии и уйти по своим делам, пощелкать впн и т.п. Кстати работает не только со скриптами.<br><br>Наверное есть еще варианты провернуть подобное. Я показал способ которым пользуюсь сам.<br><br><strong>Ключевые слова для самостоятельного гугления:</strong> bg, fg, jobs, disown, nohup.<br><br><em>Да, после того как нажал ctrl+z, можно все откатить назад, запускаешь команду fg и ловишь флешбек.<br><br></em>Такие вот дела. Хорошего тебе вторника и не болей!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-80">

      <div class="body details">
9 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message161">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="09.11.2023 14:12:55 +07">
14:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем привет кого не видел и новеньким. Нас тут уже овер 10к единомышленников, растем!<br><br><em>Вопрос из зала — я бывший java разработчик, подался в девопсы, теперь неспешно изучаю bash. Подскажите, если какая-то альтернатива конструкции try/catch? <br><br></em>Начнем с того, что бывших разработчиков не бывает. Даже если ты выйдешь из айти и начнешь ловить крабов, айти не выйдет из тебя. Проверено многолетним опытом и не только моим.<br><br>Ну а по делу, <strong>try/catch в bash — нет</strong>. На этом можно было бы и закончить, но увы... давай обсудим. <br><br>Аналогичного поведения можно добиться используя логический оператор <strong>||. <br><br>Например:<br><br></strong><pre>command1 || command2<br><br></pre>Если первая команда вывалит ошибку, то отработает вторая команда. Ну чем не <strong>try/catch,</strong> Даже лучше! Правда концепция работы не такая как в других языках.<br><br><strong>На практике это выглядит так:<br><br></strong><pre>false || echo &quot;error, returned false&quot;<br><br></pre>Сейчас сработает <strong>catch</strong> и выведет <strong>«error, returned false»,</strong> так как команда <strong>false</strong> всегда возвращает ошибку. Статус: <strong>exit 1.<br><br></strong>А если <strong>false</strong> заменить на <strong>true, </strong>но сработает <strong>try</strong> и в терминале ничего не отобразится. Бесподобно. <br><br>Итоговая конструкция будет такой:<br><br><pre>#!/bin/bash<br><br>{ # try<br>    echo &quot;hello bashdays&quot;<br>    false<br>    <br>} || { # catch<br>    echo &quot;error, returned false&quot;<br>}<br><br></pre>Для <strong>catch</strong> можно сделать отдельную функцию. Которая будет автоматически включать режим дебага (<strong>sex -x</strong>) либо какие-то другие свистоперделки для отладки.<br><br>Вообще <strong>это больше относится к костылям</strong> и подобное можно реализовать с таким же успехом на IF’ах. А можно банально проверять статус выхода, <strong>если &gt; 0 то кирдык.</strong> <br><br>Я такие конструкции не использую, максимум втыкаю в начала скрипта <strong>set -e.</strong> Если статус команды будет<strong> &gt; 0,</strong> то немедленно всё выпадет в осадок.<br><br>Тут нет правильных и неправильных решений. Как говорится если работает, то уже хорошо. Остальное детали.<br><br>Если есть чего добавить, велком в комментарии. Возможно у тебя есть секретный модуль для <strong>bash с try/catch</strong>.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-81">

      <div class="body details">
12 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message163">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.11.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Не будем нарушать воскресных традиций. Утреннее чтиво.<br><br>Давай покумекаем, <strong>чем отличаются файлы .bashrc .bash_profile .profile и т.п.<br><br></strong>Вообще про это особо никто не задумывается, если что-то требуется сделать, обычно запихивают всё в <strong>.bashrc.</strong> Но почему именно туда? А нахрена тогда нужен <strong>.profile?<br><br></strong>Основное различие этих конфигурационных файлов заключается в том, что некоторые из них читаются только оболочками входа (login). Например, при входе в систему с другого хоста или при входе в текстовую консоль локальной unix-машины. Используются файлы <strong>.login .profile .zlogin.</strong> Зависит от того какая у тебя оболочка.<br><br>Далее идут конфигурационные файлы, которые читаются «интерактивными» оболочками. То есть подключенными к терминалу или псевдотерминалу. Это файлы с именами <strong>.bashrc, .tcshrc, .zshrc и т.д.<br><br></strong>Файл <strong>.bashrc</strong> читается только интерактивной и <strong>non-login</strong> оболочкой, поэтому большинство людей в конечном итоге инклудят в файле <strong>.bash_profile</strong> чтение файла <strong>.bashrc,</strong> например:<br><br><pre>[[ -r ~/.bashrc ]] &amp;&amp; . ~/.bashrc<br><br></pre>Другие оболочки ведут себя по-другому. Например, в <strong>zsh,</strong> файл <strong>.zshrc</strong> всегда читается для интерактивной оболочки, независимо от того, является ли она <strong>login</strong> или нет.<br><br>А файл <strong>.profile,</strong> это просто сценарий входа в систему. И изначально использовался в <strong>/bin/sh.</strong> Оболочка Bash, будучи обратно совместимым с <strong>sh,</strong> будет читать <strong>.profile,</strong> если он конечно же существует.<br><br><strong>Пример файла .profile<br><br></strong><pre>if [ &quot;$BASH&quot; ]; then<br>  if [ -f ~/.bashrc ]; then<br>    . ~/.bashrc<br>  fi<br>fi<br><br></pre>Как видим, при login’е заинклудится файл .<strong>bashrc.<br><br></strong>Классически <strong>~/.profile</strong> используется в <strong>Bourne Shell.</strong> И вероятно, поддерживается Bash как устаревшая мера. Опять же <strong>~/.login</strong> и <strong>~/.cshrc</strong> использовались оболочкой <strong>CShell</strong> (csh).<br><br><em>В дистрибутивах семейства Debian сначала выполняется .profile, а потом уже .bash_profile. А вот в дистрибах производных от RHEL, сначала выполняется .bash_profile, а уже потом .profile. Ну вот прям каша! </em><br><br>Короче как обычно развели зоопарк, одно читает другое, чтобы заработало третье. Масло-масляное. А есть же еще всякие <strong>.environment,</strong> у которого ноги растут из <strong>Korn Shell</strong> (ksh).<br><br>Вот по этой причине никто особо и не вникает, почему все манипуляции обычно производятся в файле <strong>.bashrc.</strong> Этот файл обычно есть везде и всегда, а большего и не нужно.<br><br>В документации bash хорошо объясняется, при каких обстоятельствах читается каждый файл. И поведение на разных машинах в целом одинаково.<br><br>Выжимка из <strong>man bash:<br><br></strong><pre>/bin/bash - The bash executable<br>/etc/profile - The systemwide initialization file, executed for login shells<br>/etc/bash.bashrc - The systemwide per-interactive-shell startup file<br>/etc/bash.bash.logout - The systemwide login shell cleanup file, executed when a login shell exits<br>~/.bash_profile - The personal initialization file, executed for login shells<br>~/.bashrc - The individual per-interactive-shell startup file<br>~/.bash_logout - The individual login shell cleanup file, executed when a login shell exits<br>~/.inputrc - Individual readline initialization file<br><br></pre>Если есть чего добавить, велком в комментарии. Ладно, вечерком затроним какую-нибудь техническую часть, а может быть и подебажим. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message165">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.11.2023 20:03:01 +07">
20:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Давай повелосипедим и напишем <strong>таймер на со-процессах,</strong> без использования каких-то внешних команд типа <strong>sleep</strong> и т.п.<br><br><pre>#!/bin/bash<br><br>coproc read <br>read -t 0.10 -u &quot;${COPROC[0]}&quot;<br>echo &apos;new velosiped&apos; <br>read -t 11 -u &quot;${COPROC[0]}&quot;<br>exit</pre><br><br>1. Создаем фоновый со-процесс read<br>2. Спим 0.10 секунды<br>3. Выводим на экран new velosiped<br>4. Опять спим, но уже 11 секунд<br>5. Выходим<br><br>За указания задержки, как раз отвечает параметр <strong>-t.</strong> А параметр <strong>-u</strong> говорит что чтение данных нужно осуществлять с файлового дескриптора запущенного в фоне со-процесса. Белиберда? Еще какая!<br><br><em>В sleep, кстати тоже можно указывать миллисекунды: sleep 0.10</em><br><br><em>Со-процессинг это одновременное выполнение двух процедур, одна из которых считывает вывод другой.</em><br><br>Чтобы запустить со-процесс, используется зарезервированное слово <strong>coproc.</strong> Доступ к этому со-процессу осуществляется посредствам массива <strong>COPROC</strong>.<br><br><strong>${COPROC[0]}</strong> - для записи<br><strong>${COPROC[1]}</strong> - для чтения<br><br>В реализации такого таймера есть и подводные камни. Таймер может отставать как механические часы, это зависит от загруженности самой системы.<br><br>Если запустить одну команду <strong>coproc read,</strong> на экран выведется <strong>PID</strong> запущенного в фоне процесса <strong>[1] 126594.</strong> Чтобы посмотреть список запущенных в фоне команд, выполняем <strong>jobs</strong> и видим список:<br><br><pre>[1] Running coproc COPROC read &amp;<br>[2] Running coproc COPROC read &amp;<br>[3] Running coproc COPROC read &amp;</pre><br><br>То есть получается ты запускаешь в фоне какую-то программу, а в другой программе, подключаешься через массив <strong>COPROC</strong> записываешь либо считываешь нужные тебе данные.<br><br><strong>Еще пример:</strong><br><br><pre>coproc awk &apos;{print $2;fflush();}&apos;<br>echo bom bim bom &gt;&amp;${COPROC[1]}<br>read -ru ${COPROC[0]} var<br>echo $var</pre><br><br>По итогу получаем вывод на экран, слово: <strong>bim</strong><br><br><strong>Давай попробуем попроще:</strong><br><br><pre>coproc (echo $(whoami))<br>read -r user &lt;&amp;&quot;${COPROC[0]}&quot;<br>echo $user</pre><br><br>1. Создаем со-процесс, который в фоне выполнит <strong>whoami</strong><br>2. Прочитаем в переменную <strong>user</strong>, то что вывел со-процесс<br>3. Выводим на экран, у меня отобразилось <strong>root</strong><br><br><strong>Фуф, тут вроде более понятно получилось объяснить.</strong> Ну а если не понял, значит оно нахер тебе и не нужно.<br><br>Короче без бутылки тут не разобраться, это из оперы «высший пилотаж» и брейнфак.<br><br><strong>Зачем это нужно и где применять? </strong>Понятия не имею. Я обычно не лезу в со-процессы, это усложняет скрипт, а коллеги которые не в теме, вообще не смогут его поддерживать. <br><br><strong>Ну и на закуску, совсем уж упороться:</strong><br><br>Несколько команд, которые помогут понять, как вся эта шляпа реализована.<br><br><pre>coproc read<br>echo &quot;${COPROC[@]}&quot;<br>ls -l /proc/$$/fd | grep &apos;pipe&apos;<br>ls -l /proc/$COPROC_PID/fd | grep &apos;pipe&apos;</pre><br><br>1. Создаем со-процесс<br>2. Выводим содержимое массива COPROC<br>3. Выводим каналы текущей оболочки.<br>4. Выводим каналы со-процесса.<br><br>Смотрим на имена, биты разрешений (r/w) ссылок и на что они указывают.<br><br><strong>Как сказал один западный эксперт:</strong><br><br><blockquote>Пока я не могу придумать никаких задач для со-процессов, по крайней мере не являющихся надуманными.</blockquote><br><br>Вот такие пироги, изучай.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-82">

      <div class="body details">
15 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message166">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="15.11.2023 14:06:01 +07">
14:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Доброе всем! Я как ценитель всяких бумажных Bullet Journal и подобных ежедневников, в какой-то момент перегорел. Стало лень писать ручкой, заполнять задачки и планировать рабочий день. Не знаю по какой причине это произошло.<br><br>Но скорее всего по причине — если ты спланировал свой день, 100% все пойдет <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">попизде</span></span> не по плану. Это как со скрам спринтами, спланировали спринт, тут же прибежала озабоченная обезьяна и насувала в кабину «очень» срочных задач. Понятно дело, это на подсознании отлично демотивирует. <br><br>Но без личного таск-трекера опять же никуда. Носить в голове 100500 задач, рабочих, бытовых и т.п. не вариант. Сейчас ты помнишь, что нужно было оплатить домен, а через секунду уже не помнишь. Классика. <br><br><em>Я так недавно промотал оплату корпоративного VPN и пришлось в срочном порядке платить со своей личной карты. Естественно потом мне бабки никто не вернул. Бюрократия. Игра не стоит свеч.<br><br></em>По крайней мере у меня так. Поэтому я стараюсь все выгружать из головы в одно место. Нет, не в жопу. Раньше на бумагу, а теперь прям в консольный <strong>TaskWarrior.</strong> Щас расскажу, что это за пепяка такая. <br><br><strong>TaskWarrior</strong> это консольный трекер-задач с открытым исходным кодом. Черношляпы еще его называют ТуДу-ВуДу лист для хакеров.<br><br>Короче, открываем консольку… <br><br><blockquote>У меня вообще с этим отлично реализовано в iTerm. Консолька открывается в Drop-down режиме по нажатию F1. То есть сверху вниз, поверх всех окон выезжает мой основной рабочий инструмент. Ну и также закрывается. Привык, ОЧЕНЬ удобно! Под линуксы и винду такое тоже реализуемо и есть из коробки. Отдельный пост про это надо будет запилить.<br><br></blockquote><strong>Давай создадим в TW первую таску:<br><br></strong><pre>task add &quot;Написать пост про taskwarrior&quot;<br><br></pre>Всё! Задачка в бэклоге и про нее уже не забудешь, можно смело выкидывать из головы и торжествовать.<br><br>Конечно же предварительно <strong>taskwarrior</strong> нужно установить, есть под все операционки и дистрибутивы. Дока по установке <a href="https://taskwarrior.org/download/">тут</a>. Ставится на уровне пакетных менеджеров, но можно и через исходники скомпилировать если ты любитель прекрасного.<br><br>Как говорится на этом можно и закончить. Но хотелось бы еще посмотреть список всех задачек, которые мы создали. Для этого фигачим:<br><br><pre>task ls<br><br></pre>И получаем желаемый список Ну а чтобы пометить таску как выполненную, делаем:<br><br><pre>task done 1/2/3/4/5<br><br></pre>Подставляем индекс таски, которую нужно закрыть. Всё! Это основное. Простота и удобство! Не думай что <strong>TW</strong> на столько ущербен, там из коробки просто нереальный функционал. Но я использую наверное процента два от всего возможного.<br><br>Дополнительно у меня создано 2 проекта, home и work. По ним раскидываю задачи, которые относятся к домашним делам и рабочим. Чтобы было проще ориентироваться и выводить нужные на экран.<br><br>Чтобы синхронизировать заметки и задачи между устройствами, нужно поднять свой ламповый сервер. Будет единая точка входа с базой данных. А там уже цепляйся к нему хоть с писюка хоть с андроида/ios, и крути педали. Удобнее конечно через docker-compose все поднимать.<br><br>Для удобства я сделал себе несколько алиасов, теперь мне не нужно каждый раз писать task и название проекта.<br><br><pre>alias th=&quot;task project:home add &quot;<br>alias tw=&quot;task project:work add &quot;<br>alias tlh=&quot;task project:home ls &quot;<br>alias tlw=&quot;task project:work ls &quot;<br><br></pre>В общем в <strong>TW</strong> полный минимализм и отличная кастомизация для всех любителей консольных штук. Еще можно настроить цвета, приоритеты, поглядеть отчеты и многое другое. Но мне хватает коробочного варианта. В общем всем советую потыкать.<br><br><strong>💩</strong><a href="https://taskwarrior.org/">страница проекта<br></a><strong>🐱</strong><strong> </strong><a href="https://github.com/GothenburgBitFactory/taskwarrior">страница на гитхабе<br></a><a href = "stickers/AnimatedSticker (8).tgs">💩</a> <a href="https://bitbucket.org/kvorobyev/taskwarriorandroid/">клиент для андроида</a><strong> и </strong><a href="https://f-droid.org/en/packages/me.bgregos.brighttask/">тут<br></a><a href = "stickers/AnimatedSticker (9).tgs">💩</a> <a href="https://apps.apple.com/de/app/task-add/id1553253179">клиент для айфона<br><br></a>Как это выглядит визуально, можешь глянуть <a href="https://telegra.ph/TaskWarrior-11-15">тут</a>, подзалил нативно картичночки. А <a href="https://taskwarrior.org/download/task-2.3.0.ref.pdf">тут</a> крутой sheets по tw.<br><br>Ладно, убежал. Если бухгалтерию разгребу, вечерком чего-нибудь забашим или обсудим!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a> <a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-83">

      <div class="body details">
16 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message167">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.11.2023 19:03:02 +07">
19:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Тут недавно у нас в <a href="https://t.me/bashday">чатике</a> пролетал способ <strong>как скрыть процессы в Linux от других пользователей.</strong> Пожалуй этот момент стоит поподробнее просветить и тут. Тема интересная.<br><br>К примеру есть многопользовательский сервер. Юзера конектятся к нему по ssh. И я не хочу чтобы какой-нибудь там Василий Волоёбович знал, что у меня запущена порнокачалка.<br><br>По идее если запустить pstree, ps, htop и др. То мы увидим процессы не только свои, но также системные и пользовательские.<br><br><strong>Чтобы скрыть свои процессы</strong> от других пользователей, всего лишь <strong>нужно перемонтировать </strong><a href="" onclick="return ShowBotCommand(&quot;proc&quot;)">/proc</a><strong> с опцией hidepid. <br><br></strong><em>Работает только с пользователями, рут будет по-прежнему в курсе запущенной порнокачалки.<br><br></em>Параметр <strong>hidepid</strong> определяет какую информацию о процессах мы ограничим для пользователей, которые не являются владельцами этих процессов.<br><br><strong>Параметры которые можно задать:<br><br>hidepid=0</strong> - Включена по умолчанию, все видят всё, полный доступ к <strong>/proc/PID/.<br><br>hidepid=1</strong> - Разрешает обращаться к информации только о своих процессов. Часть файлов в каталоге <strong>/proc/PID/</strong> защищена от любопытных морд.<br><br><strong>hidepid=2</strong> - Это тот же самый <strong>hidepid=1</strong> + всё в <strong>/proc/PID</strong> будет невидимо для других пользователей. Граница на замке.<br><br>Чтобы убедиться, что ты видишь процессы других, запусти от обычного пользователя например htop. В левой колонке будут имена пользователей, root, грут, пруд, фрукт, daemon, syslog и т.п.<br><br><strong>Давай теперь закроем этот «бэкдор».<br><br></strong>Запускаем от рута:<br><br><pre>mount -o remount,rw,nosuid,nodev,noexec,relatime,hidepid=2 /proc<br><br></pre>Теперь снова запускаем от обычного пользователя htop и наблюдаем интересную картину маслом. Портянка из процессов пропала, у меня осталось лишь 2 штуки, bash и htop. Красота!<br><br>Естественно после ребута сервера, вся эта красота сгинет. А чтобы этого не произошло, зафигач монтирование <a href="" onclick="return ShowBotCommand(&quot;proc&quot;)">/proc</a> в fstab.<br><br><strong>Вставляем в /etc/fstab<br><br></strong><pre>proc /proc proc defaults,nosuid, nodev, noexec,relatime,hidepid=2 0 0<br><br></pre>Вот и всё. Но есть одно НО. Встречаются приложения которые могут отвалиться. Для этого нужно захотфиксить маунт с опцией <strong>gid=VALUE.<br><br></strong>Значением <strong>gid</strong> параметра может быть имя группы в системе, членам которой доступ к процессам будет разрешён. И затем маунтить <a href="" onclick="return ShowBotCommand(&quot;proc&quot;)">/proc</a> таким образом:<br><br><pre>proc /proc proc defaults, hidepid=2, gid=bashdays 0 0<br><br></pre>Добавляем пользователя от имени которого будет работать приложение/демон в эту группу и проверяем — если всё сделано верно, то зафакапленное приложение заработает как обычно.<br><br>Такие дела. Изучай. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-84">

      <div class="body details">
17 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message169">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.11.2023 18:03:26 +07">
18:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Animation
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
31.2 KB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Мои студенты недавно интересовались, <strong>как и чем я делаю запись экрана с терминала.</strong> Поделюсь и с вами. <br><br>Начнем с того, что я не записываю терминал в реальном времени. Сначала я создаю сценарий, который в автоматическом режиме будет печатать нужные мне команды. А на выходе получается полноценный gif файл.<br><br>Софтина называется <strong>VHS. </strong>Позволяет<strong> ЧЕРЕЗ КОД </strong>записать gif файл. <strong><br><br>VHS</strong> написана на модном golang. Для начала устанавливаем. Есть под все операционки, в <a href="https://github.com/charmbracelet/vhs#installation">документации</a> найди свой дистрибутив и накопипасти в терминал.<br><br>Я ничего не устанавливал, а пользуюсь docker версией, мне так удобнее, все зависимости упакованы в контейнер. Но если от докера тебя выворачивает, можешь всегда собрать всё это из исходников.<br><br><strong>Создаем файл сценария bashdays.tape<br><br></strong><pre>vim bashdays.tape<br><br></pre><strong>И пишем код:<br><br></strong><pre>Output bashdays.gif<br>Require echo<br><br>Set Shell &quot;bash&quot;<br>Set FontSize 32<br>Set Width 1920<br>Set Height 1080<br><br>Type &quot;echo &apos;Hello this is BashDays&apos;&quot; Sleep 500ms  Enter<br>Type &quot;apt install -y nginx&quot; Sleep 500ms Enter<br><br>Sleep 5s<br><br></pre>Думаю тут все интуитивно понятно, откроется оболочка bash, настроятся шрифты, высота, длиннота и сообщение которое будет напечатано. Либо команда, которая будет выполнена. Настроек там дофига, но как обычно 90% никем не используются.<br><br>После того как сценарий готов, запускаем:<br><br><pre>docker run --rm -v $PWD:/vhs ghcr.io/charmbracelet/vhs bashdays.tape<br><br></pre>Наблюдаем за процессом создания и <strong>на выходе получаем файл bashdays.gif.</strong> В котором будет вывод строки через echo и процесс установки nginx.<br><br>Получившийся <strong>gif файл можно</strong> не отходя от кассы сразу <strong>зашарить на</strong> какой-то <strong>расшаренный сервер.<br><br>Вот такой командой:<br><br></strong><pre>docker run --rm -v $PWD:/vhs ghcr.io/charmbracelet/vhs publish bashdays.gif<br><br></pre>По итогу получишь прямую ссылку вида: <code>https://vhs.charm.sh/vhs-62gl16v.gif<br><br></code>Ну а дальше уже втыкай свои гифки в корпоративные wiki, или куда там ты их втыкаешь. Короче штука ОФИГИТЕЛЬНАЯ. Всем рекомендую!<br><br><strong>🐱</strong><strong> </strong><a href="https://github.com/charmbracelet/vhs">Сраница проекта на github</a><br><br>Всех с пятницей, хороших предстоящий выходных и береги себя! <a href = "video_files/sticker (61).webm">🤩</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-85">

      <div class="body details">
19 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message171">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="19.11.2023 13:03:01 +07">
13:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>[[ ]] vs [ ]<br><br></strong>Как оказалось не каждый знает <strong>чем, отличается использование двойных квадратных скобок</strong> в скриптах <strong>от одинарных. <br><br></strong>В контексте «не каждый», из 10 человек которых я опросил, правильно ответили лишь двое и то с присказкой - мне кажется и наверное.<br><br>Я тоже одно время не обращал на это внимание. Просто писал где-то одинарные, где-то двойные, наверное от погоды зависело. Но в какой-то момент меня это начало ковырять. Пришлось разобраться. <br><br>В общем как оказалось все просто. Скрипты с двойными скобками будут работать нативно в bash и ksh. А вот во всяких POSIX оболочках таких, как например sh (и в других на основе sh) - выпадет ошибка.<br><br>А еще в двойных скобках можно использовать операторы: <strong>||, &amp;&amp;, &lt;, ==, =~.</strong> А вот с sh такое провернуть не получится.<br><br><em>При использовании оператора &lt; в двойных скобках, экранирование не нужно.<br><br></em><pre>#/bin/sh<br>[ &quot;$s &lt; abc&quot; ]<br><br>#/bin/bash<br>[[ abc &lt; abc ]]<br><br></pre>Ну и <strong>главная киллер-фича двойных скобок это</strong> - возможность пользоваться регулярными выражениями.<br><br>Примеры:<br><br><pre>#/bin/bash<br><br>s=&quot;abc123&quot;<br>[[ &quot;$s&quot; == abc* ]]         # true (globbing)<br>[[ &quot;$s&quot; == &quot;abc*&quot; ]]       # false (literal matching)<br>[[ &quot;$s&quot; =~ [abc]+[123]+ ]] # true (regular expression)<br>[[ &quot;$s&quot; =~ &quot;abc*&quot; ]]       # false (literal matching)<br><br></pre>Если заменить первую строчку на <strong>#/bin/sh, </strong>то после запуска вылетит ошибка <strong>[[: not found.<br><br></strong>Короче говоря, если хочешь чтобы твои скрипты работали везде, используй синтаксис с одинарными скобками. Но в свою очередь использование двойных скобок и связанных с ними фич, делают код более читаемым и ясным для понимания.<br><br>В общем я забил на переносимость между системами и теперь всегда использую только двойные скобки. Это как с табами и пробелами, главное однажды сделать выбор и потом этого выбора придерживаться.<br><br>Всем привет и увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-86">

      <div class="body details">
20 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message172">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.11.2023 20:02:50 +07">
20:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_23@20-11-2023_20-02-50.jpg">

         <img class="photo" src="photos/photo_23@20-11-2023_20-02-50_thumb.jpg" style="width: 260px; height: 146px"/>

        </a>

       </div>

       <div class="text">
Мы часто встречаемся с этим загадочным словом, например в контексте - Posix Shell. Но что такое этот POSIX? <br><br><strong>POSIX =  Portable Operating System Interface.</strong> Хорошо, ок, понятнее не стало. Короче это такой стандарт типа ГОСТа. <br><br>Разработали его в бородатые 80е года, а название придумал Ричард Столлман. Тот самый основатель ГНУтого движения.<br><br><strong>Задумка POSIX</strong> заключается в том, что разработчик должен создать приложение, которое будет работать в любой системе. Естественно система должна соответствовать этому стандарту.<br><br>На сегодняшний момент большинство linux дистрибутивов официально не сертифицированы POSIX. Причина одна — это дофига стоит, а у всяких создателей BolgenOS на это банально нет денег. Да и нафига? С другой стороны большинство этих дистрибутивов стараются придерживаться POSIX.<br><br>Так что когда кто-то говорит Posix Shell, это значит то, что оно соответствует стандартам. Написав скрипт который корректно запускается и работает в оболочке sh, ты можешь быть уверен, что этот скрипт будет работать — на всех линуксах.<br><br><strong>Если подытожить:</strong> для рядовых пользователей linux вся эта кухня избыточна. Мы как велосипедили, так и продолжим. Главное чтобы все работало.<br><br><em>По сути, POSIX предназначен для проектировщиков операционных систем и разработчиков программного обеспечения, но как пользователи системы мы подвержены влиянию POSIX, осознаем мы это или нет. </em><br><br>Вот теперь и ты знаешь, что такое этот POSIX. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-87">

      <div class="body details">
21 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message174">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.11.2023 02:03:01 +07">
02:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет еще раз, извиняй что поздно, так нужно. Сегодня моя продуктивность явно зашкаливает, завтра видимо пластом буду лежать как тюлень. Ладно. Давай по теме. Знал ли ты про такую команду в linux как -<strong> «yes»?</strong> Сейчас про нее и пойдет речь.<br><br>Команда <strong>yes</strong> служит для вывода в стандартный поток (stdout) строки <strong>«y»</strong> или любой другой строки. Если ее запустить по умолчанию, команда будет бесконечно сыпать строку <strong>«y».</strong><br><br>А если указать аргумент и запустить так: <strong>yes hues</strong> <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">(да - пизда)</span></span> в stdout насыпет строку <strong>«hues»</strong>. Интересно? Ну такое себе... давай дальше возбуждать интерес.<br><br>К примеру есть у тебя какая-нибудь консольная команда, которая во время своей работы будет запрашивать подтверждение, типа - а ты точно уверен, что удаляешь тестовую базу данных? Вот на такие случаи и нужна команда <strong>«yes»</strong>, чтобы не руками вводить подтверждение, а делегировать это действие.<br><br>Полезно для пайплайнов. Бывает такое, что у программы нет ключей типа <strong>apt -y install</strong>, а подтверждать как-то в автоматическом режиме нужно.<br><br><strong>Синтаксис</strong> проброса <strong>стандартный</strong>, через систему пайпов:<br><br><pre>yes | apt install nginx</pre><br><br>В примере выше, когда пакетный менеджер попросит нажать <strong>Y,</strong> команда <strong>«yes»</strong> автоматически это заапрувит и начнется процесс установки. Красота!<br><br>Не забываем, про передачу аргументов, если внешняя программа например хочет чтобы ты ввел слово: <strong>«ъyъ»</strong> делаем так:<br><br><pre>yes ъуъ | apt install nginx</pre><br><br>Но обычно на практике, в 99% случаев команда <strong>«yes»</strong> запускается без аргументов, так как большинство запрашивает именно Yes. POSIX стандарты? <a href = "video_files/sticker (62).webm">🫥</a><br><br>Прикол еще. Раз есть команда <strong>«yes»</strong> значит должна быть и <strong>«no»</strong>. Но увы, обделили! Так вот если нужно отнекиваться, передай в <strong>«yes»</strong> аргументом строку <strong>«no»</strong>. Прям лайкфак!<br><br><strong>Ааа, еще нюанс. </strong>Порой что-то может запросить простого нажатия Enter, например когда gpg ключ добавляешь для репозитория. <strong>Как послать Enter?</strong> А вот так:<br><br><pre>yes &quot;&quot; | &lt;твоя команда&gt;</pre><br><br><strong>Почему это сработает как Enter?</strong> Потому, что команда <strong>«yes»</strong> выводит в stdout не просто сроку Y, но еще и завершает ее в конце символом Enter. Вот именно поэтому при запуске чистого <strong>«yes», </strong>строчки<strong> </strong>на экране будут идти столбиком.<br><br>Собственно это всё что тебе нужно знать про <strong>«yes»</strong>. Бери на вооружение, мне пару раз пригодилась, именно в gitlab пайплайнах.<br><br>Давай, доброй ночи, завтра обязательно увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utilites&quot;)">#utilites</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message175">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.11.2023 15:03:01 +07">
15:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вчера не по своей воле дебажил веб апликуху на laravel, в 500ку сопливило. Нашел что не существует путь, куда оно хочет записать сессию, кэш и т.п. шляпу. Типа такого <strong>app/data/storage/data. Path not found.</strong> Плюсом там еще вывалило кучу вложенных папок которых не существует для нормальной работы. Ок, уже есть с чем работать.<br><br>В идеальном мире обычно разработчики сами чекают такие директории и автоматически их создают, но это в идеальном мире. На деле все иначе. Время допиливать нет, поэтому скинем эту задачу на девопсов, пусть закостылят какой-нибудь скрипт.<br><br>А как создать структуру папок из скрипта? Можно и так:<br><br><pre>mkdir /var/www/app/storage<br>mkdir /var/www/app/storage/data<br>mkdir /var/www/app/storage/data/public<br>mkdir /var/www/app/storage/data/view<br>mkdir /var/www/app/storage/data/view/public/html<br>mkdir /var/www/app/storage/data/meta<br>mkdir /var/www/app/storage/data/meta/bundle</pre><br><br>Вполне читаемо. Но если ты не знаешь, у <strong>mkdir</strong> есть аргумент, который <strong>создаст полностью структуру несуществующих папок. </strong> А если оно существует, то лишний раз орать не станет.<br><br><strong>Работает это так:</strong><br><br><pre>mkdir -p /var/www/app/storage/{data/public,data/view,data/public/html,data/meta/bundle}</pre><br><br><em>-p, --parents  = no error if existing, make parent directories as needed</em><br><br>Заметь что я отдельно не создаю папку <strong>meta</strong> и<strong> view/public</strong>, они создаются в момент создания конченных папок <strong>bundle</strong> и <strong>html.</strong><br><br>Если посмотреть strace, то видим с какими параметрами запустился mkdir<br><br><pre>execve(&quot;/usr/bin/mkdir&quot;, [&quot;mkdir&quot;, &quot;-p&quot;, &quot;/var/www/app/storage/data/public&quot;, &quot;/var/www/app/storage/data/view&quot;, &quot;/var/www/app/storage/public/html&quot;, &quot;/var/www/app/storage/data/meta/b&quot;...</pre><br><br>А можно вынести все пути в отдельный файл, а потом через цикл прогнать. Но я бы не стал по файлам раскидывать, сделал бы какой-нибудь массив путей и передал на съедение mkdir.<br><br>Как я и сказал выше, в данном контексте задачи - это костыль. Но если вернуть эту задачу на разработчиков, 100% вернется техдир и скажет - уважаемый, не делай мне нервы, СОЗДАЙ НУЖНЫЕ ПАПКИ САМ!!! Это проблема на сервере, а не в коде. В этом споре победителей не будет.<br><br>Если команда хочет костылей, она их получает. Но я все же придерживаюсь поговорки - Нормально делай, нормально будет. Хотя по большей части это справедливо лишь для моих личных проектов, где я всегда найду время и на юнит-тесты и на рефакторинг.<br><br>Хорошего вторника и увидимся вечерком.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message177">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.11.2023 23:03:24 +07">
23:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Многие тут уже в курсе, что я перелез с хакинтоша на винду + wsl. Ну дак вот. В макоси я привык работать в iTerm который <strong>работал по принципу</strong> - нажал F1 у меня сверху вниз вылез терминал. Нажал еще раз и он залез обратно. Прекрасный режим и <strong>называется он quake mode.</strong> В линуксах он тоже есть, пользовался им постоянно.<br><br>Пересев на винду я сказал в слух - пу, пу, пу.... И как жить дальше с этим Windows Terminal (Preview)? Как мне вернуться в зону комфорта и quake mode? Оказалось достаточно просто.<br><br>Добавляем в settings.json (от Windows Terminal) такую фигню:<br><br><pre>&quot;command&quot;:<br>   {<br>       &quot;action&quot;: &quot;globalSummon&quot;,<br>       &quot;desktop&quot;: &quot;toCurrent&quot;,<br>       &quot;dropdownDuration&quot;: 5,<br>       &quot;monitor&quot;: &quot;any&quot;,<br>       &quot;name&quot;: &quot;_quake&quot;,<br>       &quot;toggleVisibility&quot;: true<br>   },<br>       &quot;keys&quot;: &quot;f1&quot;<br>   },</pre><br><br>Сохраняем. И теперь <strong>по нажатию F1 у меня выезжает терминал,</strong> поверх всех окон, с любого рабочего пространства. А кнопку F1 можешь заменить на любое удобное тебе сочетание.<br><br>Так, но радость была не долгая. Терминал то выезжает, но нет TABов и чо мне делать с одним <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">гавном</span></span> окном? Мне то надо 10 серверов открыть и бегать по вкладкам. <br><br>Тут решение тоже неочевидное. Создаешь вкладку сочетанием <strong>CTRL+SHIFT+T.</strong> Открывается новый терминал, НО предыдущий куда-то исчезает! Да ёбтвоюмать! Короче утро вечера мудренее и с утра я эту тему победил.<br><br>Для переключения вкладок нужно нажать <strong>CTRL+TAB,</strong> выпадет список всех открытых вкладок, между которыми можно переключаться. Уже хорошо, НО!!!! Как без этих контролтабов визуально видеть какие вкладки у меня открыты? Утро вечера мудренее...<br><br>Пофиксил и это! Нажимаем в терминале <strong>CTRL+SHIFT+P,</strong> открывается хрен пойми какая-то менюшка. Набираем <strong>Toggle focus mode</strong> и активируем. Опа! Вкладочки появились! Теперь можно мышкой по ним кликать. Уверен что можно в settings.json этот focus включить по умолчанию.<br><br><strong>Ура! Зона комфорта возвращена!</strong> Еще был дискомфорт, что терминал выезжает лишь до середины экрана, но я сильно не стал заморачиваться и растянул его мышкой. Но всяко есть способ через конфиг сделать чтобы он на весь экран открывался. Если знаешь, маякни в комментах.<br><br>Вообще quake mode охренительно разгоняет продуктивность, а эффективность повышается. Терминал на расстоянии вытянутого пальца. Всем рекомендую подсесть на это иглу, потом слезть с нее просто так не получится. Ну удобно чо. А почему я променял макось на винду, расскажу в следующих постах.<br><br>Пока пока и хорошего вечера!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><br>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Posted
       </div>

      </div>

     </div>

     <div class="message service" id="message-88">

      <div class="body details">
23 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message178">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.11.2023 18:03:00 +07">
18:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сегодня необычный скрипт, который позволит тебе сгенерировать пароль состоящий из пробелов и прочих невидимых символов. Что-то из оперы Шрёдингера — ты никогда не узнаешь гениально это или ужасно, пока сам не попробуешь.<br><br>От этой штуки тестировщики разбегаются в ужасе. А веб-сайты на которых ты попытаешься использовать такой пароль, просто-напросто порвутся и выпустят 500ю соплю.<br><br><strong>Забрать и потыкать этот прекрасный скрипт можешь из нашей </strong><a href="https://github.com/bashdays/whitepass/blob/main/whitepass.sh">репы</a>.<br><br>Не знаю где это можно применить, но идея с паролем которого не видно, очень интересная. Я попробовал сохранить то, что получилось в bitwarden, отлично сохранился.  Да, пароль получается с симметричной защитой 128 бит.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-89">

      <div class="body details">
24 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message179">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="24.11.2023 14:03:01 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_24@24-11-2023_14-03-01.jpg">

         <img class="photo" src="photos/photo_24@24-11-2023_14-03-01_thumb.jpg" style="width: 196px; height: 260px"/>

        </a>

       </div>

       <div class="text">
Привет. Наткнулся вчера на <strong>CheatSheet по Расширенным параметрам в Bash.</strong> Довольно неплохой и понятный. PDF версию можешь забрать <a href="https://d.cxcore.net/Bash/bash-parameter-expansion-cheatsheet.pdf">отсюда.</a><br><br><strong>Что такое расширенные параметры?</strong> Ну если коротко: допустим есть у меня переменная <strong>${var%},</strong> что такое знак<strong> %?</strong><br><br><strong>${var%}</strong> удалит короткий суффикс<br><strong>$(var%%}</strong> удалит длинный суффикс<br><strong>${var#} &amp; ${var##}</strong> удалит короткий и длинный префикс<br><br><pre>var=&apos;hello world&apos;<br>echo ${var%world}</pre><br><br>На экран выведется слово hello. То есть произошло удаление короткого суффикса. Вариантов масса. Вот еще пример:<br><br><pre>var=&apos;hello world&apos;<br>echo ${var%o*}   # hello w<br>echo ${var%%o*}  # hell</pre><br><br><blockquote>Более подробно про расширенные параметры можно почитать на официально ГНУТой странице, с переводчиком норм заходит.</blockquote><br><br>Кстати у этого товарища <a href="https://d.cxcore.net/">здесь</a> полно всяких полезностей и документашек на все случаи жизни. Видимо отсеивает всякий шлак и собирает для себя только мастхев штуки. Поглядите на досуге, может что-то к себе переместите.<br><br>Всех с пятницей, вечером еще увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;sheets&quot;)">#sheets</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message181">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="24.11.2023 20:04:00 +07">
20:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вот и снова я. Перед выходными давай поговорим<strong> про магические числа</strong> в процессе перезагрузки Linux.<br><br>Тему эту обычно все стороной обходят, да и большинство преподов тебе никогда не расскажут что такое Magic Numbers.<br><br>Они про эти числа либо никогда не слышали, либо слышали, но не соизволили с ней ознакомиться. <strong>Поехали копаться в кишочках,</strong> как мы и любим.<br><br>Когда ты запускаешь reboot в linux, происходит масса всего интересного. Но самый главный интерес в «магических числах».<br><br>Короче «магические числа» это такая херабора из последовательности байтов, расположенных в фиксированном файле либо структуре данных. Нужны они для идентификации типа файла либо структуры. Для каждого типа файла магические числа уникальны.<br><br>Например, для ELF файлов, магические числа будут такими:<br><br><pre>ELF Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00</pre><br><br>Если система видит последовательность этих байтов, она по умолчанию делает вывод, что этот файл является ELF по первым 4м байтам. <strong>45=E, 4c=L, 46=F,</strong> перед ними стоит значение <strong>7f.</strong><br><br><strong>Посмотреть эту сигнатуру можно командой readelf:</strong><br><br><pre>readelf -h /bin/at</pre><br><br>Окей, с этим разобрались. Ну дак каким боком эти магические числа вообще связаны с командой reboot? А самым прямым!<br><br>С помощью этих чисел система определяет повреждения файловой системы. На случай если ты после ребута не сможешь загрузить сервак или свою пекарню. То есть, предостерегает и умоляет пофиксить проблему, а потом уже перезагружаться.<br><br><em>Во время процесса перезагрузки или завершения работы, система должна убедиться, что все данные записаны на диск и файловая система находится в согласованном состоянии.</em><br><br>Работает это проверка путем согласованности суперблока файловой системы.<br><br><em>Суперблок это структура данных, которая содержит информацию о файловой системе (размер, расположение блоков данных и журнала файловой системы).</em><br><br>Проверяя магическое число в суперблоке, система определяет, соответствует ли файловая система ожидаемому формату. Если магическое число похерено, значит жопа и пиши пропало, коруптед, нидхелп.<br><br><em>Отсюда и растут ноги, когда система предлагает запустить тебе fsck.</em><br><br>Вот и при reboot система все это проверяет. Кусок исходника <strong>kernel/reboot.c:</strong><br><br><pre>/* We only trust the superuser with rebooting the system. */<br>if (!capable(CAP_SYS_BOOT))<br>    return -EPERM;<br><br>/* For safety, we require &quot;magic&quot; arguments. */<br>if (magic1 != LINUX_REBOOT_MAGIC1 ||<br>   (magic2 != LINUX_REBOOT_MAGIC2 &amp;&amp;<br>    magic2 != LINUX_REBOOT_MAGIC2A &amp;&amp;<br>    magic2 != LINUX_REBOOT_MAGIC2B &amp;&amp;<br>    magic2 != LINUX_REBOOT_MAGIC2C))<br>    return -EINVAL;</pre><br><br>Как видим <strong>magic1</strong> и <strong>imagic2</strong> присваиваются магические числа. А сами эти магические числа зашиты в файле <strong>reboot.h.</strong> При НЕ выполнении данных условий будет возвращена ошибка. <br><br><pre>/* * Magic values required to use _reboot() system call. */<br><br>#define LINUX_REBOOT_MAGIC1 0xfee1dead<br>#define LINUX_REBOOT_MAGIC2 672274793<br>#define LINUX_REBOOT_MAGIC2A 85072278<br>#define LINUX_REBOOT_MAGIC2B 369367448<br>#define LINUX_REBOOT_MAGIC2C 537993216</pre><br><br><strong>Первая строчка 0xfee1dead</strong> звучит забавно - <strong>чувствую себя дохлым</strong> или<span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true"> мне пезда</span></span>! Именно эта константа и отвечает за перезагрузку системы.<br><br><strong>Остальные числа:</strong><br><br><strong>672274793</strong> зашифрован ДР Линуса Торвальдса<br><strong>85072278</strong> ДР дочки Линус Патрисия Миранда<br><strong>369367448</strong> ДР дочки Линус Даниел Юланда<br><strong>537993216</strong> ДР дочки Линус Целеста Аманда<br><br><strong>Нормальная пасхалочка!</strong> Чтобы расшифровать эти числа и получить человечные даты ДР можно воспользоваться командой:<br><br><pre>printf -v d &apos;%x&apos; 672274793 ; echo &quot;Linus ${d:0:2}-${d:2:2}-${d:4}&quot;</pre><br><br>Вот такие пироги под капотом этого нашего Linux.<br><br><em>Кстати команда file извлекает данные о файле как раз из магических чисел и заголовков.</em><br><br>Ладно, всем хороших предстоящих выходных и берегите себя! Кстати про суперблоки отдельно попозже разбор сделаю.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-90">

      <div class="body details">
27 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message182">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.11.2023 19:04:21 +07">
19:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, выходные пролетают со скоростью света и так по кругу. Порой задумываешься — а что дальше? А дальше поговорим про <strong>особенность ядра linux как zram.</strong><br><br><strong>ZRAM</strong> эта такая штуковина, которая <strong>позволяет сжимать оперативную память</strong> на лету и таким образом увеличить ее объём. <strong>Нет, это реально работает.</strong> А то бывают такие приколы - скачай 1гиг памяти бесплатно. Встречал в гуголплее такую хреновину для андроидов.<br><br>При включении zram, сжатие переносит часть нагрузки на процессор, но использование zram действительно может улучшить производительность. Особенно на серваках/пекарнях с малым объемом оперативки.<br><br>Также есть zswap, которая сжимает данные в разделе подкачки. И которая по умолчанию включена почти во всех официальных ядрах.<br><br>Проблема zswap заключается в том, что его приоритет выше чем у zram, который остается неиспользуемым. Чтобы решить эту проблему, нужно задизейблить zswap в ядре.<br><br><pre>CONFIG_ZSWAP_DEFAULT_ON=N</pre><br><br>Но чтобы применить эту опцию, нужно пересобрать ядро. А оно нам нафиг не всралось. Поэтому пойдем легким путем и задизейблим zswap через загрузчик grub.<br><br><strong>Редактируем файл /etc/default/grub</strong><br><br><pre>GRUB_CMDLINE_LINUX_DEFAULT=&quot;zswap.enabled=0&quot; loglevel=3 quiet &quot;</pre><br><br><strong>Не забываем перегенирировать конфиг grub:</strong><br><br><pre>grub-mkconfig -o /boot/grub/grub.cfg</pre><br><br><strong>Перезагружаем машину</strong> и проверяем отключение zswap:<br><br><pre>cat /sys/module/zswap/parameters/enabled</pre><br><br><strong>Если вывелась буква N значит ты все сделал правильно.</strong><br><br><em>Кстати можешь изначально проверить, возможно zswap у тебя по умолчанию выключен. У меня в Selectel сразу выводит букву N, возможно по причине, что у меня вообще swap отсутствует.</em><br><br><strong>Ну и наконец включаем zram.</strong> Для этого пишем bash скрипт и кидаем его в автозагрузку:<br><br><pre>#!/bin/bash<br><br>modprobe zram<br>mkdir /sys/block/zram0<br>echo lz4 &gt; /sys/block/zram0/comp_algorithm<br>echo 1G &gt; /sys/block/zram0/disksize<br>echo 2 &gt; /sys/block/zram0/max_comp_streams<br>mkswap --label zram0 /dev/zram0<br>swapon --priority 100 /dev/zram0</pre><br><br>1. Загружаем модуль zram<br>2. Выбираем алгоритм сжатия lz4 (либо zstd)<br>3. Объем zram, у меня 1гиг физической оперативки<br>4. 2 это количество потоков сжатия (потоки процессора)<br>5. Создаем блочное устройство и включаем его<br><br>Запускаем скрипт и проверяем включение командой: <strong>zramctl.</strong> Если на экран что-то вывелось, значит всё ок и сжатие начало работать.<br><br>Если заморачиваться с bash скриптами не хочется, ставим утилиту которая будет работать через systemd.<br><br><pre>apt install systemd-zram-generator</pre><br><br><strong>Правим конфиг /etc/systemd/zram-generator.conf</strong><br><br><pre>[zram0]<br>zram-size = ram<br>compression-algorithm = lz4</pre><br><br><strong>Активируем и запускаем:</strong><br><br><pre>systemctl daemon-reload<br>systemctl start /dev/zram0</pre><br><br>Всё! Теперь оно само будет запускаться без лишних движений.<br><br>Ну и не забываем про минус использования zram. При включении ты теряешь возможность использовать нативный swap раздел. По крайней мере так написано в мануале. Но это не точно.<br><br>Надо будет ради интереса бенчмарки снять. Хотя тут наверное проще гуглануть, всяко кто-то уже снимал.<br><br>Ладно пойду дальше кубернейтсы шатать. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message183">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.11.2023 22:24:36 +07">
22:24
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_25@27-11-2023_22-24-36.jpg">

         <img class="photo" src="photos/photo_25@27-11-2023_22-24-36_thumb.jpg" style="width: 260px; height: 212px"/>

        </a>

       </div>

       <div class="text">
ну раз пошла такая пьянка, минутка юмора, ребята тут глобальные проблемы решают... и не поспоришь...<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><br>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-91">

      <div class="body details">
28 November 2023
      </div>

     </div>

     <div class="message default clearfix" id="message184">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.11.2023 21:07:34 +07">
21:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
01:00, 3.8 MB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Хеллоу май диа френдз! Я тот еще любитель интерактивных штук, особенно консольных, где чето можно стрелочками побегать, понажимать, с минимумом геморроя. Короче фетиш у меня на всякие потыкать.<br><br>Приобщился тут к утилите <strong>hstr,</strong> которая выводит историю команд в формате списка. А в этом списке уже стрелками можно перемещаться по истории. Но это не главное. Лично я использую ее исключительно в режиме фильтрации.<br><br><em>HSTR (HiSToRy) - это утилита командной строки, которая обеспечивает улучшенное bash/zsh выполнение команд из истории. Она направлена на то, чтобы сделать твою работу проще и эффективнее, чем Ctrl-r.</em><br><br>Запускаю hstr, на экран вываливается вся история, я ввожу к примеру prometheus и получаю выборку из истории, конкретно где я задрачивал prometheus. Выбираю курсором нужную мне команду и вуаля! Никаких тебе грепов и лишних телодвижений.<br><br>Рекомендую попробовать, весьма топовая штука, боюсь приживется надолго.<br><br><strong>🐱</strong><strong> </strong><a href="https://github.com/dvorka/hstr">Страница проекта на гитхаб</a><strong><br></strong><strong>💩</strong><strong> </strong><a href="http://dvorka.github.io/hstr/INSTALLATION.html">Лендинг по установке</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-92">

      <div class="body details">
1 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message185">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.12.2023 14:03:02 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Как оказалось, не все знают что nginx позволяет нативно писать логи в json формате. Вообще в продакшене это бест-практика. Для этого в конфиг nginx.conf нужно добавить такой блок:<br><br><pre>log_format nginx_json escape=json &apos;{&quot;time_local&quot;:&quot;$time_local&quot;, &quot;cloud_ip&quot;:&quot;$http_x_real_ip&quot;, &quot;ip&quot;:&quot;$http_cf_connecting_ip&quot;, &quot;connection&quot;:&quot;$connection&quot;, &quot;request_completion&quot;:&quot;$request_completion&quot;, &quot;status&quot;:&quot;$status&quot;, &quot;rtime&quot;:&quot;$request_time&quot;, &quot;rlenght&quot;:&quot;$request_length&quot;, &quot;content_type&quot;:&quot;$content_type&quot;, &quot;content_length&quot;:&quot;$content_length&quot;, &quot;bytes_sent&quot;:&quot;$bytes_sent&quot;, &quot;body_bytes_sent&quot;:&quot;$body_bytes_sent&quot;, &quot;raddr&quot;:&quot;$remote_addr&quot;, &quot;ruser&quot;:&quot;$remote_user&quot;,&quot;upstream_addr&quot;:&quot;$upstream_addr&quot;, &quot;upstr_resp_time&quot;:&quot;$upstream_response_time&quot;, &quot;upstr_cache_status&quot;:&quot;$upstream_cache_status&quot;, &quot;upst_status&quot;:&quot;$upstream_status&quot;, &quot;gzip_ratio&quot;:&quot;$gzip_ratio&quot;, &quot;http_x_forwarded_for&quot;:&quot;$http_x_forwarded_for&quot;, &quot;proxy&quot;:&quot;$proxy_host:$proxy_port&quot;, &quot;proxy_int_body_length&quot;:&quot;$proxy_internal_body_length&quot;, &quot;server_proto&quot;:&quot;$server_protocol&quot;, &quot;rmethod&quot;:&quot;$request_method&quot;, &quot;uri&quot;:&quot;$uri&quot;, &quot;args&quot;:&quot;$args&quot;, &quot;http_referer&quot;:&quot;$http_referer&quot;, &quot;uag&quot;:&quot;$http_user_agent&quot;}&apos;;<br><br>access_log /var/log/nginx/access.log nginx_json;<br>error_log /var/log/nginx/error.log;</pre><br><br>Получаем максимальную информацию о клиенте в json формате, которую пробиваем средствами nginx. И теперь все это можно легко скармливать всяким эластикам и т.п. без парсинга и гроков. Так сказать — избавляемся от костылей.<br><br>Но хранить логи в файлах, такое себе. Поэтому мастхэв запихать логи непременно в system journal.<br><br>Забиваем пару строк в nginx.conf и всё логирование будет перенаправлено в system journal.<br><br><pre>error_log syslog:server=unix:/dev/log;<br>access_log syslog:server=unix:/dev/log nginx_json;</pre><br><br>А можно комбинировать, писать одновременно логи в файл в дефолтном шаблоне nginx’а и параллельно писать в system journal в json. Я иногда такое проворачиваю для дебага, где в логах требуется вывести лишь время, айпишник и ури-ури. Типа такого:<br><br><pre>log_format nginx_json ...<br>log_format nginx_default ...<br><br>access_log /var/log/nginx/access_json.log nginx_json;<br>access_log /var/log/nginx/access_default.log nginx_default;</pre><br><br>Но конечно если есть Kibana, дела с отладкой в разы становятся лучше. Ну а чтобы посмотреть логи в system journal, воспользуйся такой командой:<strong> journalctl -f</strong><br><br>Сегодня если руки дойдут, обсудим судо-мудо или другие линукс кишочки. Давай, хорошей тебе пятницы, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-93">

      <div class="body details">
2 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message186">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.12.2023 17:03:09 +07">
17:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Тебе частенько приходится пользоваться всякими su, sudo и т.п. Ввод этих команд зашит на подкорке в башке. Забил команду, получил результат. Но опять же особо никто не задумывается<strong> чем, отличается su от sudo</strong> + там же еще всякие непонятные ключи и дефисы. Поехали разбираться.<br><br><strong>su =</strong> «substitute user» — заменить пользователя<br><strong>sudo =</strong> «substitute user and do» - подменить пользователя и выполнить<br><br>Уже видно разницу. <strong>Различия такие:</strong> <strong>su</strong> требует пароль целевой учетной записи, на кого переключаемся. А <strong>sudo</strong> требует пароль текущего пользователя и запускает от его имени команды, которым требуются права супербога.<br><br>Например, мы сидим под пользователем <strong>user</strong> и хотим стать <strong>Иваном</strong>, делаем так:<br><br><pre>user@dev:/$ su ivan</pre><br><br>Будет запрошен пароль, нужно ввести пароль именно от учетной записи <strong>ivan</strong>, а не от <strong>user</strong>.<br><br>А вот пример с sudo:<br><br><pre>user@dev:/$ sudo -u ivan whoami</pre><br><br>А здесь нужно ввести пароль от учетной записи <strong>user</strong>, а не от Ивана или рута. Но для этого случая сперва необходимо добавить пермишены для пользователя <strong>user</strong> в файл <strong>/etc/sudoers.</strong><br><br><pre>user ALL=(ALL:ALL) ALL</pre><br><br>Редактировать этот файл можно по средствам команды <strong>visudo</strong>. А свалидировать конфиг можно командой <strong>visudo -c.</strong> Редактирование этого файла через <strong>visodu</strong> хорошо тем, что если ты накосячишь, то при сохранении, оно скажет — лось ты дырявый, тут ошибочка!<br><br>Вообще предпочтительнее использовать <strong>sudo</strong>, но если ты не криворукий можно и под <strong>su</strong> нормально работать. Ты сейчас меня конечно же осудишь, но я предпочитаю работать исключительно под root, за 20 лет пока не факапил. Ну не люблю я всякие эти судо-мудо-рыба-конь и ущемление своих серверных прав.<br><br>Окей. А для <strong>чего нужен этот странный дефис после su?</strong><br><br>А чтобы очищать переменные и пользоваться чистой оболочкой при переключении на другого пользователя. Ща покажу на котиках.<br><br>Авторизуемся под пользователем <strong>user</strong> и экспортируем переменную:<br><br><pre>ssh user@dev<br>export a=&quot;test&quot;</pre><br><br>Теперь у пользователя <strong>user</strong> есть переменная <strong>«a»</strong> которая = <strong>test.</strong><br><br>Переключаемся на пользователя <strong>ivan</strong> и смотрим переменную <strong>«a»</strong><br><br><pre>su ivan<br>echo $a</pre><br><br>Опа! <strong>Вывелась строчка test.</strong> То есть получается все что ты задал под <strong>user</strong>, перекочевало в оболочку <strong>ivan</strong>. Нормально! А теперь давай<strong> добавим дефис:</strong><br><br><pre>su - ivan<br>echo $a</pre><br><br>И пустота! Переменная <strong>$a</strong> больше не выводится. <strong>Чистая оболочка!</strong> Кстати с этим дефисом часто косячат и потом долго не могут понять в чем причина. Переменные вроде были заданы, а потом куда-то пропали. Все потому, что азов не знаем и бездумно суём этот дефис где нужно и не нужно.<br><br>Теперь ты знаешь азы и будешь с умом к этим судо-мудо подходить. По крайней мере у тебя добавится дополнительный кейс для дебага.<br><br><strong>su (с дефисом)</strong> = сначала переключается пользователь, а затем запускается shell, зачищаются все переменные.<br><br><strong>su (без дефиса) =</strong> переключает пользователя, оставляя переменные окружения старого пользователя.<br><br><strong>У sudo есть подобные ключи -s -i</strong><br><br><pre>user@dev:/$ sudo -s</pre><br><br><strong>Запустится оболочка с правами root</strong><br><br><pre>user@dev:/$ sudo -i</pre><br><br>Запустится оболочка, но уже с чтением файлов <strong>root/.profile/.bashrc и т.п.</strong> Можешь попробовать добавить экспорт переменной в<strong> .profile</strong>, сделать <strong>sudo -s/-i</strong> и увидишь что с ключом<strong> -i</strong> переменная выведется на экран.<br><br>По сути <strong>sudo -i</strong> = команде <strong>sudo su -</strong>. Но обычно за<strong> sudo su -</strong> в приличных местах выгоняют ссаными тряпками. Это плохая практика! Так как это порождает дополнительный процесс и больше гемора с набором самой команды.<br><br>Фуф… пардон за простыню, но мне нужно было тебе это рассказать. Изучай и ставь лайк. Хороших выходных. Увидимся!<br><br><em>upd: если я что-то упустил, докидывайте в комментарии, всем будет полезно.</em><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-94">

      <div class="body details">
5 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message187">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.12.2023 14:04:02 +07">
14:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Доброе утро. Возможно кто-то в прошлом месяце пропустил интересное чтиво, подборка ТОП постов:<br><br>- <a href="https://t.me/bashdays/183">Какой Linux подходит для просмотра XXX контента</a> (14270)<br>-<a href="https://t.me/bashdays/161"> Альтернатива _try/catch_ в bash</a> (10777)<br>- <a href="https://t.me/bashdays/160">Запускаем скрипт в фоне без nohup и screen</a> (10003)<br>- <a href="https://t.me/bashdays/163">Чем отличаются файлы .bashrc .bash_profile .profile</a> (8255)<br>- <a href="https://t.me/bashdays/165">Таймер на со-процессах</a> (8151)<br>- <a href="https://t.me/bashdays/169">Топовая софтина на сценариях для записи терминала</a> (7782)<br>- <a href="https://t.me/bashdays/177">Windows + WSL + quake mode terminal</a> (7381)<br>- <a href="https://t.me/bashdays/178">Генерируем пароли из пробелов</a> (7327)<br>- <a href="https://t.me/bashdays/171">Отличия [[ ]] от [ ]</a> (7285)<br>- <a href="https://t.me/bashdays/166">Taskwarrior или ТуДу-ВуДу лист для хакеров</a> (7125)<br>- <a href="https://t.me/bashdays/179">CheatSheet по Расширенным параметрам в Bash</a> (5793)<br><br>Да, вечером закину вкусное на почитать, пока в работе. Хорошего дня. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;итогимесяца&quot;)">#итогимесяца</a><em> 11/23</em><br>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message189">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.12.2023 22:07:37 +07">
22:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Фух, закончились 2 часа партнерских интеграций... Недавно я делал <a href="https://t.me/bashdays/186">пост</a> по отличиям su от sudo, но есть еще одна <strong>вкусная альтернатива, которая называется doas.</strong><br><br><em>doas – утилита, которая позволяет обычным пользователям выполнять задачи от имени root, так же как это делает sudo. Она была разработана проектом OpenBSD как минималистичная альтернатива sudo</em>.<br><br><strong>Интересно кстати звучит:</strong> do ass (делать жопу)<br><br>Утилита доступна в большинстве официальных репозиториев. Поэтому с установкой проблем не возникает.<br><br>Запускай <code>apt install «делатьжопу»</code> (или какой там у тебя пакетный менеджер) и погнали смотреть на эти булки поближе.<br><br>Так как doas не входит по умолчанию в коробочные версии linux, утилита требует немного бОльших настроек, в отличие от sudo. Но конфигурация намного проще для понимания чем sudo. Настраивается все это через файл <strong>/etc/doas.conf. </strong>Если файла нет, создай!<br><br><strong>Цель doas - решить сложность sudo.</strong><br><br>Давай эмитируем поведение sudo и позволим пользователю выполнять любые команды от пользователя root. Добавляем в конфиг такую херабору:<br><br><pre>permit persist user as root</pre><br><br>Теперь пользователь user сможет выполнять команды от root + пользователь получает льготный период, когда не нужно вводить пароль в течение нескольких минут после последовательных команд doas.<br><br>Допустим мне нужно сделать подобное, но для определенной группы, добавляем в конфиг строчку:<br><br><pre>permit persist :wheel as root</pre><br><br>Теперь все кто заключен в группу wheel смогут побыть рутом. Также и с белым списком команд, которые можно выдать для запуска без пароля:<br><br><pre>permit persist user as root<br>permit nopass :user as root cmd apt</pre><br><br>Да, конфиг более читабельный чем у sudo. <strong>И в обозримом будущем</strong> есть очень большая вероятность того, что sudo закинут в деприкейтед, а doas сделают основным рабочим инструментом. Так как sudo уже непроходимое <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">гавно</span></span> болото в плане поддержки кода, который трудно понимать и использовать.<br><br>Возьмем даже валидатор конфига visudo. Который проверяет синтаксис конфига. А это говорит о том, что синтаксис файла sudoers ну совсем фу и воняет. Требует проверки. Да и 99% пользователей используют sudo исключительно для установки софта.<br><br><strong>Разница налицо (попахивает порнохабом):</strong><br><br><strong>Конфиг sudo</strong><br><pre>%wheel ALL=(ALL) NOPASSWD: ALL</pre><br><br><strong>Конфиг «делать жопу»</strong><br><pre>permit nopass :wheel as root</pre><br><br>Ну и <strong>с помощью doas можно запустить root shell</strong> такой командой:<br><br><pre>doas -s</pre><br><br><em>Кстати был казус с портированием под FreeBSD, спустя несколько часов после публикации doas, в ней нашли критическую уязвимость. Которая позволяла выполнить привилегированные операции даже если был указан неверный пароль пользователя. Как обычно накосячил разработчик, который раздеплоился в прод без тестирования.</em> <em>Ну либо специально заложил бекдор, история умалчивает.</em><br><br>Вот такие пироги. Увидимся совсем скоро и сделаем что-нибудь полезное, например сломаем прод, ну или ногу...<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
ʜ ᴅ
       </div>

      </div>

     </div>

     <div class="message service" id="message-95">

      <div class="body details">
7 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message191">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.12.2023 21:03:12 +07">
21:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Как бы странно это не звучало, но в оболочке bash есть <strong>набор</strong> очень <strong>полезных хоткеев</strong> для эффективной работы. Держу пари многие тут пользуются только <strong>ctrl+r</strong> и <strong>ctrl+l</strong>, да чо греха таить я из этого же числа. Давай залезем поглубже и возможно возьмем что-то на вооружение.<br><br><strong>Навигация</strong><br><br><blockquote>Ctrl+A переместить курсор в начало строки<br>Ctrl+E переместить курсор в конец строки<br>Ctrl+F переместить курсор на один символ вправо<br>Ctrl+B переместить курсор на один символ влево<br>Alt+B / Esc+B переместить курсор влево на одно слово</blockquote><br><br>Хм… фигня какая-то, я пользуюсь ctrl+стрелочки, хватает.<br><br><strong>Редактирование</strong><br><br><blockquote>Ctrl+U удалить все и вернуться в начала строки<br>Ctrl+K удалить все после курсора<br>Ctrl+W удалить слово перед курсором<br>Alt+D удалить слово после курсора<br>Ctrl+Y вернуть удаленное<br>Ctrl+D удалить символ под курсором<br>Ctrl+H аналогично backspace<br>Alt+T смена позиции текущего слова на предыдущее<br>Ctrl+T замена местами двух символа перед курсором<br>Alt+U перевод слова в заглавные после курсора<br>Alt+L перевод слова в строчные после курсора<br>Ctrl+_ отмена последнего ввода</blockquote><br><br>Тут уже поинтереснее. Мне зашло преобразование в заглавные и строчные символы, не знал. Ну и откат порадовал по <strong>Ctrl+Y.</strong><br><br><strong>Bash History</strong><br><br><blockquote>Ctrl+R режим обратного поиска<br>Ctrl+P переход к предыдущей команде<br>Ctrl+N переход к следующей команде<br>Ctrl+O выполнить найденную команду<br>Ctrl+G выход из режима поиска<br>!! выполнить предыдущую команду<br>!vim выполнить последнюю команду, которая начиналась на vim<br>!vim:p вывести последнюю команду, которая начиналась на vim<br>!n запустить n команду из history</blockquote><br><br>Избыточно. Максимум оставляем Ctrl+R, остальное ну такое.<br><br><strong>Общие хоткеи</strong><br><br><blockquote>Ctrl+C завершить команду<br>Ctrl+L очистить экран<br>Ctrl+S приостановить вывод, остановить прокрутку<br>Ctrl+Q возобновить прокрутку<br>Ctrl+D закрыть оболочку<br>Ctrl+Z приостановить процесс</blockquote><br><br>Большинство из них мы с вами знаем. Из интересного это остановка прокрутки, например когда нужно приостановить вывод информации на экран и прочитать ее. <br><br>Как видим никаких киллер-фич нет. За исключением пары-тройки хоткеев. Разогнать workflow особо не получится, но для ознакомления вполне сойдет.<br><br>Если знаешь какие-нибудь еще вкусные сочетания или хаки, велком в комментарии.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-96">

      <div class="body details">
11 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message192">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.12.2023 14:02:01 +07">
14:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, дело было вечером, делать было нечего. Начнем это утро с мнемоники прав доступа. Оно нам сегодня вечером пригодится. Возможно будет сумбурно, но постараюсь разжевать. А вечером будем заниматься хитрой стеганографией на bash, как раз с помощью прав доступа.<br><br>Для стандартных трех троек прав доступа справедливо следующее:<br><br><pre> 4    2    1     # восьмеричная система  <br>r--  -w-  --x    # символьное представление  <br>100  010  001    # двоичная система</pre><br><br>Сразу обрати внимание на разряды с единицей (1) в двоичной системе счисления. Они соответствуют позициям прав доступа в символьном представлении из вывода команды<strong> ls -l.</strong><br><br><strong>Наглядная табличка соответствий:</strong><br><br><pre>- 0: 000 / —<br>- 1: 001 / –x<br>- 2: 010 / -w-<br>- 3: 011 / -wx<br>- 4: 100 / r–<br>- 5: 101 / r-x<br>- 6: 110 / rw-<br>- 7: 111 / rwx<br><br></pre>Если требуется определенный набор прав, то складываем 4, 2, 1. Первая строка это, права, которые получаются при сложении.<br><br><pre> 3     5     6     7  <br>1+2   1+4   2+4  1+2+4    <br>-wx   r-x   rw-   rwx  <br>011   101   110   111<br></pre><br>Если на пальцах, у нас есть 3 базовых цифры 1, 2, 4 которые означают такое:<br><br><pre>4 = r<br>2 = w<br>1 = x</pre><br><br>Берем эти цифры, складываем как угодно и получаем например 7, что равно 1+2+4 = rwx (читаем, пишем, исполняем).<br><br>Ладно, большинству из вас оно нахрен не вперлось, но я продолжу. У меня коллега например всегда всем ставит 777 даже не задумываясь. Мол всё работает и никогда нет проблем с доступом к файлам и папкам. Ну ок, возможно однажды встретит своего черношляпа и пересмотрит свои практики. Работает кстати в крупном банке. Только представь какой 3.14здец на серверах у него творится где наши денюжки лежат.<br><br>Давай по теме. Создаем массив:<br><br><pre>arr=({0..1}{0..1}{0..1})</pre><br><br>Получаем права в двоичной системе счисления:<br><br><pre>echo ${arr[1]}  <br>echo ${arr[2]}  <br>echo ${arr[3]}  <br>echo ${arr[4]}  <br>echo ${arr[5]}  <br>echo ${arr[6]}  <br>echo ${arr[7]}</pre><br><br>На экран выведется:<br><br><pre>000<br>001<br>010<br>011<br>100<br>101<br>110</pre><br><br>В bash <strong>при указании индекса массива можно применять арифметические операции.</strong> Давай воспользуемся и наглядно посмотрим как суммируются права доступа.<br><br><pre>echo ${arr[1+2]}  <br>echo ${arr[1+4]}  <br>echo ${arr[2+4]}  <br>echo ${arr[1+2+4]}</pre><br><br>Получаем:<br><br><pre>010<br>100<br>101<br>110</pre><br><br>То есть когда мы делали<strong> arr[1]</strong> у нас было <strong>000</strong>, а когда применили сложение <strong>arr[1+2], 000+001 = 011.</strong><br><br>В общем математика и кишочки. Голову сильно не забивай, в повседневных задачах достаточно восьмеричной и символичной системы счислений. <strong>Из полезного:</strong> теперь ты знаешь как создавать массивы и складывать их.<br><br>Ну и на закуску команда, которая выведет права в восьмеричной системе:<br><br><pre>stat -c&apos;%a %n&apos; /tmp/*</pre><br><br><strong>Получим такое:</strong><br><br><pre>700 snap-private-tmp<br>700 ssh-XXXXXX5Fyxmr<br>700 ssh-XXXXXXENecCm<br>700 ssh-XXXXXXkPO9QF<br>700 systemd-logind.tkfPcb<br>700 systemd-r1KRzA<br>777 test.txt</pre><br><br>Не забываем что у всей этой ерунды есть еще дополнительные биты, это когда права указываются четырьмя цифрами.<br><br>Короче базу рассмотрели, если ничо не понял, забей. Это как Джаз, чтобы от него блевать не хотелось, нужно стать старым пердуном. Но мы же с вами еще так молоды!<br><br>Увидимся вечером. Хорошего понедельника!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message193">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="11.12.2023 19:03:27 +07">
19:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Как и обещал, сегодня у нас с тобой хитрая стеганография на bash. Не скажу что тема простая, но будут готовые инструменты, которые можно взять и использовать. Не вникая в кишки.<br><br>Как говорится - чтобы что-то спрятать, нужно поместить это на видное место.<br><br><strong>Начнём со спойлера:</strong><br><br><pre>ls -l /tmp/box<br><br>-rw---x--- <br>-rw----r--<br>-rwx--xr--<br>-rw-r-----<br>-rw--w----<br>-rw----r--<br>-rwxr--r--<br>-rwx--xr--</pre><br><br>Пока ничего не понятно, а если я сделаю так:<br><br><pre>./mode2char /tmp/box<br><br>-rw---x---     (610)<br> 1100010 (98)  (&apos;b&apos;)<br><br>-rw----r--     (604)<br> 1100001 (97)  (&apos;a&apos;)<br><br>-rwx--xr--     (714)<br> 1110011 (115) (&apos;s&apos;)<br><br>-rw-r-----     (640)<br> 1101000 (104) (&apos;h&apos;)<br><br>-rw--w----     (620)<br> 1100100 (100) (&apos;d&apos;)<br><br>-rw----r--     (604)<br> 1100001 (97)  (&apos;a&apos;)<br><br>-rwxr--r--     (744)<br> 1111001 (121) (&apos;y&apos;)<br><br>-rwx--xr--     (714)<br> 1110011 (115) (&apos;s&apos;)<br><br>bashdays</pre><br><br>Сечешь фишку? <strong>Это и называется стеганография.</strong> Я спрятал в правах файлов скрытое сообщение «bashdays». Вот тут нам и пригодилась <a href="https://t.me/bashdays/192">тема</a> с правами доступа и всякими этими системами счислений. Давай разбираться как это работает.<br><br><em>Сами bash скрипты mode2char и char2mode закину в конце поста на гитхаб.</em><br><br>В примере выше у меня сопоставляются права доступа с диапазоном символов <strong>32..126 (ASCII)</strong>. Если номер 7ми битной кодировки ASCII сдвинуть на два бита, то получаем как раз те самые 9 бит прав доступа.<br><br><strong>Давай подвигаем!</strong><br><br>Распечатаем диапазон ACSII символов 32..126 в восьмеричном формате:<br><br><pre>for i in 10 {32..126} ; do printf &apos;%03o\n&apos; $(( i &lt;&lt; 2 )) ; done</pre><br><br>На экран вывалится куча всего, что-то похожее на права доступа:<br><br><pre>372<br>376<br>380</pre><br><br>Чтобы преобразовать в обратную сторону делаем так:<br><br><pre>for i in 440 524 545 ; do echo $(( 8#$i &gt;&gt; 2 )) ; done</pre><br><br>То есть сдвигаем вправо на 2 бита. Из цифр <strong>440, 524, 545</strong> - получили<strong> 72, 85, 89.</strong><br><br>Ну а теперь всю эту херню ненаглядную, преобразуем в читаемые символы.<br><br><pre>for i in 440 524 545 ; do printf -v hex &apos;\\x%x&apos; $(( 8#$i &gt;&gt; 2 )) ; echo -e &quot;$hex&quot; ; done</pre><br><br>Вот это поворот! Странно что на такую строчку антивирус не триггернулся. В общем теперь на экране красуется всем известное слово.<br><br>Помнишь <a href="https://t.me/bashdays/192">я сегодня писал</a>, что единицы двоичного представления прав доступа, соответствуют символам <strong>rwx</strong>, а нули символу<strong> «-».</strong> Таким образом можно легко получить закодированный символ вручную подставляя 0 и 1 в нужных местах.<br><br>А <a href="https://github.com/bashdays/mode2char/blob/main/char2mode">вот </a>и сам скрипт, который разбивает строку и генерирует кучку файлов с нужными правами доступа. В скрипте не используются сдвиги, работает всё через ассоциативные массивы для декодирования.<br><strong><br>Запускается так:</strong><br><br><pre>./char2mode /tmp/box &apos;Welcome to bashdays&apos;</pre><br><br>Указываешь директорию, где создаем структуру файлов и саму строчку, которую нужно спрятать в правах доступа.<br><br><strong>Конечно есть нюансы.</strong> Скрипт будет орать если что-то не так. Существующие файлы не перезаписываются. Именование файлов соответствуют лексикографическому порядку сортировки. Это нужно для того, чтобы получить ту же последовательность файлов, что и при создании. Скрипт декодирования получает имена используя globbing, который сортирует именно так.<br><br>Сам скрипт декодирования лежит <a href="https://github.com/bashdays/mode2char/blob/main/mode2char">тут</a>, запускается аналогично:<br><br><pre>./mode2char /tmp/box</pre><br><br>При использовании скрипта декодирования, можно привязать какие угодно права к конкретному символу без какой-либо логики.<br><br><strong>Выбор велик:</strong><br><br><pre>printf &apos;%s\n&apos; {0..7}{0..7}{0..7}<br>printf &apos;%s\n&apos; {r,-}{w,-}{x,-}{r,-}{w,-}{x,-}{r,-}{w,-}{x,-}</pre><br><br>А еще же есть имена файлов, временные метки с наносекундами. Ну или вообще упороться и упаковывать более одного числа в атрибуты файла используя уникальную сортировку имен файлов.<br><br>Сложно? Конечно! Но думаю общую идею ты понял. Изучай! Увидимся совсем скоро.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-97">

      <div class="body details">
12 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message195">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.12.2023 22:04:43 +07">
22:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_26@12-12-2023_22-04-43.jpg">

         <img class="photo" src="photos/photo_26@12-12-2023_22-04-43_thumb.jpg" style="width: 260px; height: 260px"/>

        </a>

       </div>

       <div class="text">
<strong>Bash скрипт который смог...</strong><br><br>Думал отдельный канал сделать под такой формат, но решил не заниматься <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">хуйнёй</span></span> ерундой и порой постить своё творчество прям сюда. Благо создается оно под настроение. Валить мемами не собираюсь, хватает мне <a href="https://t.me/+RgVVsZkSl942Nzky">псины</a> и <a href="https://t.me/+TULl5Vtx7g1iNTJi">гардена</a>. Не обессудьте <a href = "video_files/sticker (50).webm">🥳</a><br><em><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;hokku&quot;)">#hokku</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-98">

      <div class="body details">
13 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message197">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.12.2023 15:03:01 +07">
15:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Зашел тут разговор, а<strong> зачем люди делают touch, перед тем, как что-то записать в файл?</strong> Причем так делает большинство, да и в учебниках повсюду это пихают. Но какой в этом смысл, если при записи все равно будет создан файл? Я имею в виду такую ситуацию:<br><br><pre>touch file.txt<br>vim file.txt<br>:w</pre><br><br>все же проще:<br><br><pre>vim file.txt<br>:w</pre><br><br>И не нужно никакого touch. Так откуда взялась эта дурная привычка? И дурная ли она? Почему мы не делаем тогда типа такого?<br><br><pre>dd if=/dev/zero of=newfile bs=1 count=0</pre><br><br>Оно ведь тоже создает новый файл…<br><br><strong>На самом деле правильного ответа нет.</strong> Единственно что нужно знать, это — используя touch ты всегда будешь уверен, что сможешь записать свои данные в файл.<br><br>А не когда набрал в vim кучу текста, сохраняешь, а оно тебе <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">идикатывхуй</span></span>, permission denied. Файл есть, но владелец кто-то другой. Короче говоря <strong>это быстрый способ выяснить, если ли у тебя права на запись</strong>, прежде чем ты начнешь редактирование.<br><br>Да и еще touch используется для обновления даты модификации. Кстати очень удобная штука. Например, ты редактировал конфиг nginx в прошлом году, но всем нужно показать что вчера, делаешь<strong> touch nginx.conf</strong> и проставляется актуальная дата и время. И в bash скриптах можно использовать, если есть какая-то логика с lock файлами, таймштампами и т.п.<br><br><strong>А как правильно создавать файлы?</strong> А просто! Правильный способ для создания файлов, это любая команда, которая использует системный вызов <strong>create</strong> или <strong>open</strong> (с флагом O_CREATE). Таких команд и программ дофига.<br><br>Вообще ситуацию можно сравнить с grep, мы его используем, потому что не знаем ничего лучше. Старая школа и мышечная память. Ну или сравним с гуглом и chatgpt, я знаю что gpt найдет и даст ответ быстрее, но я все же предпочитаю гуглить. <br><br>А все мифы о том, что в старых linux с ядром 0.97 нужно было обязательно использовать touch, всего лишь мифы.<br><br>Кстати есть еще такой древний строковый редактор, называется <strong>ed.</strong> Идет в коробке почти со всеми дистрибутивами. Этот редактор изначально требовал наличия файла перед его редактированием. И да, из этого редактора выйти намного сложнее чем из vim. Попробуй ради интереса.<br><br>Как-то так. А как ты создаешь файлы?<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message198">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.12.2023 23:03:29 +07">
23:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Много вопросов поступило про ASCII после моего демонического <a href="https://t.me/bashdays/193">поста</a>. Этот пост будет не лучше, крепись<a href = "video_files/sticker (63).webm">🙂</a><br><br>Конкретно есть интерес — как можно переводить и узнавать номера символов в различных системах счисления.<br><br>Ну смотри, давай выведем значения номеров символа английского алфавита в кодировке ASCII (шестнадцатеричные, восьмеричные, десятичные). <strong>Возьмем за эталон символ «S».</strong><br><br>В bash это можно провернуть таким способом:<br><br><pre>printf &apos;Hex : %x Oct : %o Dec : %d\n&apos; &quot;&apos;&quot;S{,,}  <br>printf &apos;Hex : %x Oct : %o Dec : %d\n&apos; &apos;&quot;&apos;S{,,}  <br>printf &apos;Hex : %x Oct : %o Dec : %d\n&apos; \&apos;S{,,}  <br>printf &apos;Hex : %x Oct : %o Dec : %d\n&apos; \&quot;S{,,}</pre><br><br><strong>Получим:</strong><br><br><pre>Hex : 53 Oct : 123 Dec : 83</pre><br><br>Это специальный синтаксис команды printf. Если перед символом <strong>«S»</strong> идет одинарная кавычка, или двойная кавычка, то значение будет номером символа.<br><br><em>Такой синтаксис появился в bash с версии 2.05a. Added support for builtin printf &quot;&apos;&quot; flag character as per latest POSIX drafts.</em><br><br>Аналогично можно узнать номер символа в многобайтовой кодировке UTF-8.<br><strong><br>Например, так:</strong><br><br><pre>printf &apos;Hex : %x Oct : %o Dec : %d\n&apos; &apos;&quot;&apos;Я{,,}</pre><br><br>На всю эту чачу влияют переменные окружения <strong>LC_CTYPE</strong> и <strong>LC_ALL</strong>. Ща покажу. Запускаем такое:<br><br><pre>( LC_ALL=C ; chunks=&quot;Сёма&quot; ; echo ${chunks:0:1}${chunks:3} )</pre><br><br>Кодировка сломалась, на экран вывелось «Бма». Мы получили доступ к байтам, а не к символам UTF-8 кодировки. Второй байт символа <strong>«С»</strong> отправляется на помойку и аналогично первый<strong> «ё»</strong>. По итогу вместо «Сёма» мы получили «Бма».<br><br><blockquote>Установка LC_ALL=C может использоваться для обеспечения непрерывности в работе программы, независимо от языковых настроек окружающей среды. Это может быть полезно, если вам нужно гарантировать, что вывод программы или результат выполнения команды не зависит от текущей локали системы.</blockquote><br><br>Если интересно более глубже погрузиться в весь этот 3.14здец UTF-8, можешь прочитать эту замечательную <a href="https://www.cl.cam.ac.uk/~mgk25/unicode.html">статью</a>.<br><br>Так, опять от темы ушли. Наверняка тебя интересует, <strong>что означает конструкция {,,}</strong>. Это бородатый хак, который дублирует строки.<br><br><pre>echo bashdays{,,,}</pre><br><br>На выходе получим 4 раза слово bashdays. Ничего сложного. Бери на заметку, хак полезный.<br><br>А еще команда printf, позволяет присвоить результат переменной. Делается это так:<br><br><pre>printf -v var &apos;Hex : %x Oct : %o Dec : %d\n&apos; &apos;&quot;&apos;Ж{,,}<br>echo &quot;$var&quot;</pre><br><br>Пока на этом всё. Больше не смею тебя мучить этими ужасными вещами! Увидимся завтра.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-99">

      <div class="body details">
14 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message200">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="14.12.2023 16:02:38 +07">
16:02
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, сейчас покажу интересную bash фичу. Которая ну совсем уж не очевидная и про нее мало кто знает. <br><br>В bash скрипте можно хранить данные, закодированные в base64. Выглядит это следующим образом:<br><br><pre>#!/bin/bash<br><br>read_data() {<br>  mapfile -t DATASET &lt; &lt;(sed &apos;1,/^DATASET/d&apos; &quot;$0&quot; | base64 -d)<br>}<br><br>read_data<br><br>echo ${DATASET[@]}<br><br>exit 0<br><br>DATASET<br>SGVsbG8gQmFzaERheXM=</pre><br><br>Функция<strong> read_data</strong> считывает данные из самого скрипта. С помощью <strong>sed</strong> удаляются строки от начала файла до строки <strong>DATASET</strong>. А затем происходит декодирование оставшихся данных. В конце всё сохраняется в массив <strong>DATASET</strong> с помощью <strong>mapfile</strong> и выводится через <strong>echo.</strong><br><br>Красота! Мой скрипт по итогу выведет на экран <strong>«Hello BashDays»</strong>. Где это можно применить, понятия не имею. Возможно тебе удастся это куда-нибудь приспособить.<br><br><em>Еще в этом скрипте мне не нравится exit 0, если есть мысли как от него избавиться, велком в комментарии. Я чет покопался вчера, но так пока и не победил. Если убрать exit 0, оно будет работать, но в конце грязно выругается.</em><br><br>Бери на вооружение, возможно твой стартап нуждается в этом. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-100">

      <div class="body details">
17 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message201">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.12.2023 20:03:18 +07">
20:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Надо было тут провести экстренные технические работы на сервере. Сервер публичный и смотрит жопой в интернет.<br><br>Клиенты это обычные пользователи, которые заходят по ssh и пытаются на практике изучать bash и linux. Короче студенты какого-то крупного ВУЗа, а сервер выступает подопытным стендом для всяких лабораторных работ.<br><br>Клиентов дофига (человек 800) предупредить о технических работах нет никакой возможности. А если бы и была, то 99% не увидят электронных писем с важной информацией и начнут долбать саппорт.<br><br>Задача вроде тривиальная, но нужно было предварительно задропать все сессии + не разрешать повторно подключить. Ну и естественно каким-то хреном выслать уведомление всем тем, кого задропали в моменте.<br><br>На самом деле тут все просто. Создаем пустой файл<strong> /etc/nologin.</strong> Теперь только root сможет авторизоваться по ssh. Да, предварительно нужно разрешить вообще заходить под root’ом.<br><br><strong>Часть задачи решили. </strong>Теперь нужно уведомить бедолаг, которые в данный момент что-то делают в терминале. Пусть сохраняют свои поделки и отправляются на заслуженный отдых.<br><br>Для этого воспользуемся утилитой <strong>wall.</strong><br><br><em>Wall — утилита командной строки, которая отображает сообщение на терминалах всех вошедших в систему пользователей.</em><br><br><strong>Запускаем команду:</strong><br><br><pre>wall &quot;Быстренько сохраняемся и валим с сервера. В 10:15 сервер уходит в запой.&quot;</pre><br><br>Все кто был подключен к серверу, получают сообщение:<br><br><pre>Broadcast message from root@dev (pts/0) (Sun Dec 17 11:38:21 2023):<br>Быстренько сохраняемся и валим с сервера. В 10:15 сервер уходит в запой.</pre><br><br>И неважно что делает человек и где находится, сообщение появится у него на экране. Через wall кстати можно спамить определенным группам пользователей.<br><br>Ну все, ответственность с себя сняли. <strong>В 10:15 запускаем ассасина:</strong><br><br><pre>pkill -9 -u `who | awk &apos;{print $1}&apos;| grep -v root|head -1</pre><br><br>Вот так вот грубо мы выгнали всех с сервера, кроме root’а. Вот и все, спокойно проводим технические работы, удаляем<strong> /etc/nologin</strong> и радуемся какие мы молодцы.<br><br><strong>Wall</strong> можно заменить например на такое:<br><br><pre>echo &quot;Hello from BashDays&quot; | write user</pre><br><br>Но тут сообщение уйдет конкретному пользователю <strong>user</strong>. Конечно если по какой-то причине отсутствует <strong>wall</strong> в системе, можно и через цикл выгрести всех юзеров и через echo скормить им уведомление.<br><br><em>write - утилита, позволяющая отправить сообщение другому пользователю, который имеет сессию в этой же системе.</em><br><br>Ну либо так:<br><br><pre>echo &quot;Hello from BashDays&quot; &gt; /dev/pts/1</pre><br><br>Пытался сделать так <strong>/dev/pts/[0-9]*,</strong> но чет не проканало, заорала как потерпевшая. Ну это всё костыли, в общем неважно.<br><br>Ладно, хорошо тебе провести остаток выходного, увидимся завтра.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-101">

      <div class="body details">
18 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message203">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.12.2023 22:04:11 +07">
22:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Тишина у каждого своя, у всех в душе свои оркестры…</strong><br><br>Как мы с тобой знаем, в начале скрипта принято использовать строку <strong>shebang/hashbang.</strong> Это то самое, которое <strong>#!/bin/bash.</strong> Конечно его не обязательно ставить, но рекомендуется. Ранее этот вопрос разбирался <a href="https://t.me/bashdays/145">здесь</a>.<br><br>Так, но порой вместо привычной нам конструкции, можно встретить нечто подобное:<br><br><pre>#!/usr/bin/env bash<br>#!/usr/bin/env python<br>#!/usr/bin/env python3</pre><br><br>Да, с питончиком тоже такая чача бывает. Но что это за сракафак и зачем? В нашем случае такое хитрое указание интерпретатора имеет смысл. <br><br><strong>Основная идея env bash</strong> это улучшение переносимости. Никто не может гарантировать, что интерпретатор находится по захардкоженому пути.<br><br>Указал ты допустим в скрипте <strong>#!/bin/bash</strong>, закинул скрипт на сервер, а эндпоинта <strong>bin/bash</strong> нет. По этой причине господа ребята используют хак с <strong>env</strong> <strong>bash</strong>. Использование <strong>env</strong> позволяет снизить риски за счет запуска команды на основе данных из переменной среды <strong>PATH</strong>.<br><br>Ну и используя <strong>env</strong> в скрипте можно указывать любые версии интерпретатора. Возможно у тебя стоит две версии <strong>bash</strong>, ну или как распространено с питончиком. Деприкейтед 2.7 и трёшка. Думаю мысль ты уловил. Чтобы не править скрипты, можно подменять версии интерпретаторов и даже сами интерпретаторы.<br><br><strong>Давай посмотрим на практике.</strong><br><br><pre>mkdir ~/bin<br>cp /bin/sh ~/bin/bash<br>export PATH=~/bin:$PATH<br>env bash</pre><br><br>1. Создаем папку <strong>bin</strong> в домашнем каталоге<br>2. Копируем интерпретатор<strong> sh </strong>в<strong> ~</strong><a href="" onclick="return ShowBotCommand(&quot;bin&quot;)">/bin</a>, но обзываем его bash<br>3. Экспортируем новый путь <strong>~</strong><a href="" onclick="return ShowBotCommand(&quot;bin&quot;)">/bin</a> в <strong>PATH</strong><br>4. Запускам <strong>bash</strong> через <strong>env</strong><br><br>Дела… у нас <strong>запустился интерпретатор sh</strong>. То есть <strong>~/bin/bash</strong> (обращаем внимание на знак <strong>~</strong> = домашняя директория пользователя) был найден раньше, чем просто <strong>/bin/bash.</strong><br><br>Если посмотреть <strong>PATH</strong> мы увидим следующее:<br><br><pre>echo $PATH<br>/root/bin:/root:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin</pre><br><br>Наш домашний каталог с бинарниками стал приоритетным. И если теперь в скриптах указать <strong>#!/usr/bin/env bash</strong> то запустится<strong> sh</strong> из <strong>~</strong><a href="" onclick="return ShowBotCommand(&quot;bin&quot;)">/bin</a>. Ничего сложного. Но на практике обычно никто такой хераборой не занимается. Чисто для примера, ну или для совсем уж костылей, когда нужно быстро и вчера.<br><br><strong>Преимущества c env:</strong><br><br>- Запуск интерпретатора не из конкретно указанного места, а из того что встретилось первым в переменной окружения <strong>PATH</strong>. <br><br><strong>Недостатки:</strong><br><br>- Путь <strong>/usr/bin/env</strong> банально может не существовать. Но обычно существует.<br><br>Ну и если используешь <strong>env</strong>, в него можно прокинуть параметры, делается через ключик<strong> -S</strong>:<br><br><pre>#!/usr/bin/env -S var1=a var2=b bash --help</pre><br><br><strong>Venv в Python</strong> работает по такому же принципу, реврайтит <strong>PATH</strong> и позволяет использовать разные версии.<br><br><pre>&gt; index.py<br>python3 -m venv .venv<br>source .venv/bin/activate<br>import sys<br>print(sys.executable)<br><br>/tmp/.venv/bin/python</pre><br><br>Если посмотреть <strong>PATH</strong> (<code>echo $PATH</code>) при активации <strong>venv</strong>, то увидим совершенно другой <strong>PATH</strong>:<br><br><pre>/tmp/.venv/bin:/home/user/bin:/usr/local/opt/libpcap/bin:/home/user/.pyenv/bin:/opt/homebrew/opt/openjdk/bin</pre><br><br>То есть к нашему <strong>PATH</strong> добавился каталог <strong>/tmp/.venv/bin,</strong> который стал приоритетнее чем <strong>/home/user/bin.</strong><br><br>Вот так вот это всё и работает под капотом. Я эти <strong>env</strong> по большей части никогда не использую, хреначу <strong>#!/bin/bash</strong> и погнали, пока всегда и везде работало. Конец!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-102">

      <div class="body details">
20 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message204">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.12.2023 14:03:00 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_27@20-12-2023_14-03-00.jpg">

         <img class="photo" src="photos/photo_27@20-12-2023_14-03-00_thumb.jpg" style="width: 260px; height: 164px"/>

        </a>

       </div>

       <div class="text">
Привет. Утренний микропост. Короче когда перенаправляешь вывод результатов в файл, то на экране нифига не видно. Но порой это бывает критично, а нужно и в файл записать и глазками позырить в реалтайме. <br><br>На этот случай у нас есть утилита <strong>tee</strong>, которая как раз этой хераборой и занимается.<br><br><pre>command | tee log.txt</pre><br><br>На картинке хорошо видно, откуда произошло название <strong>tee</strong>, это буква <strong>T</strong> в произношении. Вывод затекает сверху слева и вытекает в двух направлениях. Ты видишь происходящее на экране, а параллельно это происходящее записывается и в файл. Удобно.<br><br><strong>Вот как нужно называть утилиты!</strong> Взял произношение буквы и можно в коробку упаковывать. Кстати пока писал, вспомнил что английская <strong>«H»</strong>, взяло название от <strong>Eighth</strong> - то есть восьмая буква алфавита. Короче никто особо не заморачивался с неймингом.<br><br>Ну а еще есть подобная утилита, называется просто <strong>script</strong>. Она позволяет записать всё происходящее на экране сразу в файл. Работает даже в интерактивном режиме. Запустил ты ее и работаешь в консоли, а она пишет все твои действия в кабачок.<br><br>Ключей у нее много разных, если интересно можешь глянуть хелпину. Видел что её подключают в bashrc чтобы логировать все действия криворуких обезьян.<br><br>Я ни <strong>tee</strong> ни <strong>script</strong> не использую, потому что всё время про них забываю, да и особой необходимости нет.<br><br>Такие дела. Вечерком закину еще чтива, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message206">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.12.2023 19:03:18 +07">
19:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<em>Это пост изобилует грубыми и матерными выражениями и, в силу своего содержания, вообще не предназначен для просмотра лицам с нежной и хрупкой психикой.</em><br><br><strong>Довелось мне тут побывать на ретроспективе</strong>. Это пиздец ребята. Не буду писать про прелюдии и чекины, это тот еще артхаус.<br><br>Короче на вопрос «оцените как прошел этот спринт цифрами от 1-5». Я воткнул естественно 5ку. Ну а чо, факапов нет, продакшены работают, команда довольна, входящие отбиты, бэклог пустой. Условия ГПХ выполняются. Твердая пятерка!<br><br><em>Да, бэклог может быть пустым!</em><br><br>Но как оказалось, 5ка это нихуя не хорошо, это ПЛОХО! На моё удивление — вы чо там грибов пережрали в своём айти или скрамом упоролись? <br><br>Ответ проджекта (или как там это тело правильно называется) — Рома, если кто-то ставит 5ку, значит этот человек НЕ загружен задачами на 100%. А возможно вообще сидит на жопе ровно и специально на планировании втыкает стори-поинты в свою пользу.<br><br>Хм подумал я… напугали кота сосиской, но ничего не ответил. Больные блять, я так-то и на планирование не хожу. А я то думаю, чо все четверки понаставили. Опытные бродяги.<br><br>То есть получается оценка спринта 1, 2, 3 и 5 это плохо. Какой-то прям гнилой скрам получается. Ну да черт с ним. Если уж еще раз попаду на это безумное мероприятие, буду ставить 5 и всех бесить.<br><br>Ладно, пережили, забыли. НО спустя пару дней, ко мне приходит ТОП менеджер и говорит — Господин Роман, у нас сложилось такое впечатление, что вы нихуя не делаете. Ваши утренние отчёты выглядят как гавно:<br><br><blockquote>вчера<br>- текущие задачи<br>сегодня<br>- текущие задачи</blockquote><br><br>Что вы скажете в своё оправдание? А давайте вы теперь будете нам писать прям подробным списком, какие задачи делаете!<br><br>Да блять! Проснулись. В том-то и дело, что я нихуя не делаю, я уже сделал и слежу, чтобы это работало 24/7/365. Ну раз хотите чтива, будут вам подробные отчеты.<br><br>Позиция понятна, ребят чет понесло не туда, ну бывает… Ну и теперь каждое воскресение я захожу в GPT и клепаю бездушные отчеты на следующую неделю. Закидываю их в телеграм отложку и продолжаю наслаждаться своей зоной комфорта. Ну и ТОП менеджеры позже заапрувили, что теперь всё ок! <br><br>Эта история закончилась на позитивной ноте, все остались довольны. Но первый звоночек прозвенел, посмотрим что будет дальше.<br><br><em>Есть такая прекрасная поговорка — Прод висит на нитке, а думают о прибытке!</em><br><br>Спасибо, что дочитали, мне нужно было с вами этим поделиться. Хорошего всем утра-дня-вечера-ночи. На связи!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-103">

      <div class="body details">
25 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message207">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="25.12.2023 14:03:00 +07">
14:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Давно не виделись, конец года, все как с ума посходили, всем нужно вчера и срочно. Надеюсь у тебя тоже все хорошо. Сегодня поделюсь задачей которую решал на днях для клиента, связанную со swap. <br><br><strong>Задача от заказчика: </strong>У меня есть приложение, которое уходит в swap, мне нужно чтобы оно туда не уходило. Сам swap отключать нельзя.<br><br>Задаю очевидный вопрос — а зачем? Чтобы что? Ну свапится оно, ну и пусть свапится, никогда с этим проблем ни у кого не встречал.<br><br>Как оказалось, они там провели у себя какие-то хитрые тесты и доказали, что если их приложение начинает свапится, то это влияет на скорость его работы. Ну да, есть в этом доля правды. Если на сервере достаточно RAM, можно и реализовать это безобразие.<br><br>А решается эта задача через cgroups.<br><br><em>cgroups (Control Groups) представляют собой механизм в ядре Linux для ограничения, изоляции и управления ресурсами, предоставляемыми группам процессов. Они предоставляют интерфейс для создания и управления группами процессов, а затем накладывают ограничения на ресурсы, потребляемые этими группами.</em><br><br>Сначала ставим необходимые пакеты, если они не стоят:<br><br><pre>apt-get install cgroup-tools</pre><br><br>Создаем отдельную группу <strong>asshole</strong>, в нее будем добавлять приложения, которые нужно оградить от swap:<br><br><pre>cgcreate -g memory,cpu:/asshole</pre><br><br>Запрещаем вытеснять процессы в swap:<br><br><pre>echo 0 | tee /sys/fs/cgroup/asshole/memory.swap.max</pre><br><br>Добавляем процесс в группу <strong>asshole</strong>:<br><br><pre>cgclassify -g memory,cpu:/asshole/ $(pidof nginx)</pre><br><br>Для примера я добавил nginx, который не будет уходить в swap. Но ты можешь добавить все что угодно.<br><br>Дополнительно для группы <strong>asshole</strong> отключим OOM:<br><br><pre>echo 1 | tee /sys/fs/cgroup/asshole/memory.oom.group</pre><br><br>Вот и всё, теперь приложение не будет уходить в swap и OOM (Linux Out-Of-Memory Killer) обломается. <strong>Ну и как вариант:</strong> всё нахуй встанет раком, продакшен издаст последний вздох и упадет в новогодние праздники. Но тут, как говорится — хозяин барин! Хотели отключить, отключили.<br><br>Все настройки производились на ubuntu 22.04, в других версиях есть различия на названия <code>memory.swap.max, memory.oom.group</code> и прочее.<br><br>После создания группы, зайди, посмотри что у тебя там создалось. И от туда уже пляши. У меня этот способ не сработал на виртуальных серверах в Селектеле (permissions denied), но прекрасно сработал в Digital Ocean и на локальной виртуалке.<br><br>Экспериментируйте! Кстати после перезагрузки, cgroups слетят и по возможности создавай юнит в systemd, типа такого:<br><br>/<strong>etc/systemd/system/asshole.service</strong><br><br><pre>[Unit]<br>Description=My cgroup configuration<br><br>[Service]<br>ExecStartPre=/bin/mkdir -p /sys/fs/cgroup/asshole<br>ExecStartPre=/bin/mount -t cgroup -o memory asshole /sys/fs/cgroup/asshole<br>ExecStart=/bin/echo 1 &gt; /sys/fs/cgroup/asshole/memory.oom.group<br><br>[Install]<br>WantedBy=default.target</pre><br><br><pre>systemctl daemon-reload<br>systemctl start asshole<br>systemctl enable asshole</pre><br><br>Хорошего понедельника! И всегда помни, если что-то ограничиваешь, рано или поздно оно взбунтуется и сделает уйму головняков.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-104">

      <div class="body details">
26 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message208">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.12.2023 21:06:01 +07">
21:06
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:04, 806.7 KB
          </div>

         </div>

        </div>

       </div>

       <div class="text">
Ребята, что я вам принёс! Кринжатину! Офигительная консольная, мульти-плеерная <strong>игруля под названием «piu-piu»</strong>.<br><br><strong>Под капотом нативный Bash + ANSI.</strong> Подозреваю изобрел её наш русскоговорящий соотечественник, судя по локализации терминала на видео.<br><br><strong>Суть игрушки:</strong> Летим на вертолёте,<strong> управляем wasd</strong>, <strong>стреляем на «p»</strong> и уничтожаем вражеские юниты. Жизни и патроны расходуются. Но это еще не всё, в игре <strong>присутствует режим penis mode.</strong><br><br><strong>Как пишет автор</strong> — если тебе не достаточно весело, запускай игру так:<br><br><pre>penis=big ./piu-piu</pre><br><br>Бери друга и вперед! В два ствола летать гораздо веселее. Так же присутствует режим дуэли, который позволит выяснить у кого прибор длиннее. Выясни это здесь и сейчас!<br><br>А в последнем обновлении, добавлен эффект трясущегося хозяйства. Вообще у разработчика большие планы на этот проект, обещают добавить кастомизацию размеров с плавающей точкой.<br><br><em>Если у тебя еще остались друзья, можешь нехило зарубиться!</em><br><br>Ставится элементарно через apt (но версия не последняя), либо сливаешь себе репозиторий, чмодишь на «икс» и запускаешь.<br><br>На выбор либо вертолет, либо penis mode. Сам уже отталкивайся от своих предпочтений.<br><br>Здесь <a href="https://github.com/vaniacer/piu-piu-SH">страница проекта</a> и мануалы как ставить. Погнали!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;games&quot;)">#games</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message209">

      <div class="body">

       <div class="pull_right date details" title="26.12.2023 21:06:01 +07">
21:06
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:05, 973.8 KB
          </div>

         </div>

        </div>

       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message210">

      <div class="body">

       <div class="pull_right date details" title="26.12.2023 21:06:01 +07">
21:06
       </div>

       <div class="media_wrap clearfix">

        <div class="media clearfix pull_left media_video">

         <div class="fill pull_left">

         </div>

         <div class="body">

          <div class="title bold">
Video file
          </div>

          <div class="description">
Not included, change data exporting settings to download.
          </div>

          <div class="status details">
00:07, 1.4 MB
          </div>

         </div>

        </div>

       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-105">

      <div class="body details">
27 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message212">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.12.2023 17:04:00 +07">
17:04
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всех рад видеть, привет! Сразу к делу. В оболочке Bash есть такая настройка, как <strong>«set -k»</strong>, если по ней вызвать хелп, то получим следующее:<br><br><blockquote>-k  All assignment arguments are placed in the environment for a command, not just those that precede the command name.</blockquote><br><br>То есть, при активации этой настройки, все что будет похоже на присваивание переменным значений, поместиться в среду команд. И совершенно не важно, где в строке находится это присваивание.<br><br>Короче говоря, если в команде используется синтаксис присваивания (HUY=512), то эта команда не получит этих присвоенных опций в качестве аргументов. Чтобы стало понятнее, давай на практике.<br><br><pre>set -k  <br>dd if=/dev/zero of=/dev/null count=1 bs=2048</pre><br><br>По идее, команда <strong>dd</strong> должна прочитать блок размером <strong>2048 байта</strong> из устройства<strong> /dev/zero</strong> и записать эти байты в устройство <strong>/dev/null</strong>. А после выполнения — завершить работу.<br><br>На экран должны получить нечто подобное:<br><br><pre>1+0 records in<br>1+0 records out<br>2048 bytes (1.0 kB, 1.0 KiB) copied, 9.4642e-05 s, 10.8 MB/s</pre><br><br>Но так как мы выполнили <strong>«set -k»</strong>, все будет иначе. Утилита <strong>dd</strong> не получит указанных опций в качестве аргументов и будет пытаться читать и писать блоками по <strong>512 байт</strong> (512 по умолчанию). После выполнения команды, мы получаем — <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">Хуй с маслом</span></span>! Ничего! Хотя ожидали получить — завершение работы.<br><br>Выполнив <strong>«set -k»</strong> утилита <strong>dd</strong> просто заблокировалась на чтении стандартного потока ввода и ожидает данные. Вот такие перлы!<br><br>Обожаю угорать над студентами, сначала втихую активируем <strong>«set -k»</strong> и просим решить простую задачку со звездочкой. Но задачка почему-то не решается. А дальше начинается гогул, strace и бессонные ночи.<br><br>Если нарвался на подобное поведение, как вариант, проверь этот самый <strong>«set -k»</strong>. Деактивировать эту фигню, так: <strong>«set +k»</strong>.<br><br><em>Всегда ору с этого синтаксиса, плюс = отключить, минус = включить.</em><br><br><strong>Для чего вообще нужна «set -k» и где применяется?</strong> Возможно для фоновых процессов, ну либо угорать над студентами. Если знаешь истинное применение, пиши в комменты, будет интересно.<br><br>Давай, увидимся вечером, хорошего тебе дня!<br><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message213">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.12.2023 22:03:31 +07">
22:03
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет еще раз кого не видел. Давай сейчас <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">из гавна и палок</span></span> изобретем полезняшку. Создаём текстовый файл: <strong>~</strong><a href="" onclick="return ShowBotCommand(&quot;bashdays&quot;)">/bashdays</a> и вставляем в него такое содержимое:<br><br><pre>$if mode=emacs<br>&quot;\&quot;&quot;: &quot;\C-v\&quot;\C-v\&quot;\C-b&quot;<br>&quot;&apos;&quot;: &quot;\C-v\&apos;\C-v\&apos;\C-b&quot;<br>&quot;`&quot;: &quot;\C-v\`\C-v\`\C-b&quot;<br>&quot;(&quot;: &quot;\C-v\(\C-v\)\C-b&quot;<br>&quot;[&quot;: &quot;\C-v\[\C-v\]\C-b&quot;<br>&quot;{&quot;: &quot;\C-v\{\C-v\}\C-b&quot;<br>$endif</pre><br><br><strong>Загружаем эти макросы из файла:</strong><br><br><pre>bind -f ~/bashdays</pre><br><br><strong>Теперь при вводе кавычки или скобки в терминале, они будут автоматически закрываться</strong>. А курсор удобно разместится между этими символами. Как в лучших традициях современных IDE с плагинами.<br><br>Работает корректно в Bash, с настройками по умолчанию. Чтобы каждый раз это не биндить, пропиши ту же самую строчку в <strong>.bashrc/.inputrc.</strong> Или сразу глобально в <strong>/etc/inputrc</strong> если есть супер-юзер.<br><br><strong>Нюансы:</strong><br><br>Они есть, но вряд ли встретятся у тебя. Но все равно расскажу.<br><br>1. Макрос работает только в режиме emacs. Если не работает, возможно есть какое-то переопределение в <strong>bashrc/inputrc</strong>, типа такого:<br><br><pre>set editing-mode vi<br>set -o vi</pre><br><br>2. Не должно быть привязки функций <strong>quoted-insert, backward-char</strong> (библиотека readline) к сочетаниям <strong>\C-v, \C-b.</strong> Иначе придется править сам макрос. Проверяем:<br><br><pre>bind -q quoted-insert<br>bind -q backward-char</pre><br><br><strong>Должно вывестись примерно такое:</strong><br><br><pre>quoted-insert can be invoked via &quot;\C-q&quot;, &quot;\C-v&quot;.<br>backward-char can be invoked via &quot;\C-b&quot;, &quot;\eOD&quot;, &quot;\e[D&quot;.</pre><br><br>3. Не должно быть действующих сочетаний клавиш:<br><br><pre>&quot;\C-v\&quot;<br>&quot;\C-v&apos;&quot;  <br>&quot;\C-v`&quot;  <br>&quot;\C-v(&quot;  <br>&quot;\C-v[&quot;  <br>&quot;\C-v{&quot;</pre><br><br><strong>Проверяем:</strong><br><br><pre>bind -X | grep &apos;C-[vb].&quot;&apos;<br>bind -p | grep &apos;C-[vb].&quot;&apos;<br>bind -s | grep &apos;C-[vb].&quot;&apos;</pre><br><br><strong>Ключи:</strong><br><br><blockquote>-X = List the key sequences bound by -x in a form suitable for input to bind.<br>-p = List the names of bindable editing functions, and what their bindings are, if any.<br>-s = List key sequences that invoke macros, and their values.</blockquote><br><br>Cмотрим на левую часть, до двоеточия, у меня выдает такое:<br><br><pre>&quot;\&quot;&quot;: &quot;\C-v\&quot;\C-v\&quot;\C-b&quot;</pre><br><br>То есть все нормально. Короче такие себе грабли и вряд ли ты на них наступишь. Не знаю на сколько фича полезная, я давненько ей пользовался, но потом как-то не сложилось. Мне проще ручками проставить закрывашку, а не полагаться на какие-то хаки.<br><br>Но так или иначе, теперь и ты знаешь это, возможно в будущем или настоящем пригодится. Держи краба! Теперь уже точно, до завтра! Лайк, лайк!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-106">

      <div class="body details">
28 December 2023
      </div>

     </div>

     <div class="message default clearfix" id="message215">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.12.2023 16:07:00 +07">
16:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вчера в <a href="https://t.me/bashday">комментариях</a> к <a href="https://t.me/bashdays/213">посту</a> про <strong>«set -k»</strong>, задали вопрос про решение задачи. Чтобы понять какие опции включены в оболочке <strong>bash</strong> через <strong>«set»</strong>, достаточно выполнять команду:<br><br><pre>echo $-</pre><br><br>В этой команде <strong>«$-»</strong> представляет текущие опции командной строки. <br><br>На экран выведется, что типа такого:<br><br><pre>hikmBHs</pre><br><br>Это все опции, которые на данный момент включены в оболочке <strong>Bash</strong> через команду <strong>«set»</strong>. Ну и дальше уже можно искать проблемы с нелогичным поведением при выполнении команд. Каждая буква это опция, вызываешь хелп и смотришь что она означает.<br><br><strong>Ну или через скрипт, как мы любим:</strong><br><br><pre>if [[ $- == *k* ]]; then<br>  echo &quot;Опция -k установлена.&quot;<br>else<br>  echo &quot;Опция -k не установлена.&quot;<br>fi</pre><br><br>Про <strong>«$-»</strong> мало кто знает, в книжках я про неё никогда не встречал. В оболочке <strong>zsh</strong> эта штука тоже фурычит. Такие дела.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-107">

      <div class="body details">
2 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message216">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.01.2024 17:17:31 +07">
17:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, всех с Новым Годом! Праздники праздниками, но пора уже входить в рабочий поток и разгрести локальный техдолг. На этот раз <strong>решаем задачку с тремя известными: Windows + WSL + VirtualBox.</strong><br><br><strong>Суть такая.</strong> Понадобилось мне вхреначить на локальную машину VirtualBox с убунтой, для тестирования фичи, которую писал в <a href="https://t.me/bashdays/207">этом</a> посте. Фича не хотела заводиться на виртуальных серверах Селектела, хотя и должна была. Потребовалось убедиться, что дело не в моих кривых руках. Ладно, лирика…<br><br>Короче <strong>цепануться к убунте из wsl по ssh к VirtualBox из коробки не получилось.</strong> Да и понятно, подсети разные. Пришлось временно воспользоваться powershell и через ssh проверить гипотезу с cgroup. Винда видит подсеть виртуалки и с этим проблем нет. Проверил, забыл.<br><br>Но <strong>вопрос остался открытым:</strong> как блять/дь малой кровью из WSL (с ubuntu 22.04) подключиться напрямую к виртуалке c ubuntu 22.04 по ssh? И не задрачиваться с таблицами роутинга? Рассказываю!<br><br>Чтобы не лезть в маршрутизацию, пришлось воспользоваться стандартным функционалом проброса портов в самом VirtualBox. Жопа конечно знатно сгорела, но желаемого добился.<br><br>В общем, пиздуем в настройки VirtualBox: <strong>Сеть, Адаптер1.</strong> В нем <strong>по умолчанию включен NAT</strong>. Открываем пункт - <strong>Дополнительно</strong>, видим кнопку: <strong>Проброс портов.</strong> Заходим и начинаем заниматься <span class="spoiler hidden" onclick="ShowSpoiler(this)"><span aria-hidden="true">очередной хуитой</span></span> магией.<br><br>Сначала роутим на виндовую машину:<br><br><pre>Имя: ssh_win<br>Протокол: tcp<br>Адрес хоста: 127.0.0.1<br>Порт хоста: 2222<br>Адрес гостя: пусто<br>Порт гостя: 22</pre><br><br>Так, теперь в powershell я могу цепануться к виртуалке так:<br><br><pre>ssh -p2222 user@127.0.0.1</pre><br><br>Оно и ежу понятно, теперь усложняем задачу:<br><br><pre>Имя: ssh_win_host<br>Протокол: tcp<br>Адрес хоста: 192.168.31.100<br>Порт хоста: 22<br>Адрес гостя: пусто<br>Порт гостя: 22</pre><br><br>Этой хернёй разрешаем подключение из powershell по такому принципу:<br><br><pre>ssh user@192.168.31.100</pre><br><br>Ага, айпишник <code>192.168.31.100</code> это адрес, который выдал роутер моей виндовой машине. Как видим уже <strong>используется 22 порт.</strong> Посмотреть айпишник можно командой <strong>ipconfig</strong> в терминале powershell. Да простят меня адепты линукса.<br><br>Ну и теперь финальный штрих,<strong> прикручиваем WSL:</strong><br><br><pre>Имя: ssh_wsl<br>Протокол: tcp<br>Адрес хоста: 172.21.20.123<br>Порт хоста: 2222<br>Адрес гостя: пусто<br>Порт гостя: 22</pre><br><br>Айпишник <code>172.21.20.123</code> выдан убунте в WSL, смотрим его через <strong>ifconfig</strong>. А дальше заходим в сам WSL и подключаемся к VirtualBox как к обычному серверу:<br><br><pre>ssh user@192.168.31.100</pre><br><br>То есть цепляемся в виндовой/хостовой машине на <strong>22</strong> порт, который уже проброшен. Закидываем public ключи, делаем алиасы для быстрого коннекта. Всё! Дело в шляпе! Мы подключились из WSL (ubuntu) по ssh к виртуальной машине в VirtualBox.<br><br><strong>Есть нюанс</strong>, у меня дополнительно поднят VPN через wireguard, там еще один фактор с подсетью. Поэтому я добавил еще мусора:<br><br><pre>Имя: ssh_vpn<br>Протокол: tcp<br>Адрес хоста: 10.66.64.55<br>Порт хоста: 22<br>Адрес гостя: пусто<br>Порт гостя: 22</pre><br><br>Теперь при активации VPN, подключение к VirtualBox через WSL будет выглядеть так:<br><br><pre>ssh user@10.66.64.55</pre><br><br>Логично, адрес виндовой/хостовой машины меняется с <code>192.168.31.100</code> на<strong> </strong><code>10.66.64.55</code>. Но это детали. Еще есть тема, что при включении/выключении VPN вся это тягомотина с пробросом портов подхватывается не сразу. Имей это ввиду.<br><br>Я себе сделал 2 алиаса в wsl <strong>~/.zshrc</strong>:<br><br><pre>alias box1=&quot;ssh user@192.168.31.100&quot;<br>alias box2=&quot;ssh user@10.66.64.55&quot;</pre><br><br>Алиасы подключения без ВПН и с ВПН. Ну ты и так про это знаешь. Картинки с настройками залил <a href="https://telegra.ph/Windows--WSL--VirtualBox-01-02">сюда</a> (открываются нативно в телеграфе), заскриншотил свои поделки. Визуальнее всегда понятнее. Но у меня там дэцл хосты и айпишники по другому обзываются. Не обессудь.<br><br><em>Если знаешь более красивое решение этой задачи с пробросом, сердечно ждем в комментариях.</em><br><br>Ладно, самое время включить режим «День-Тюлень». Еще раз всех с НГ. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;wsl&quot;)">#wsl</a><em> </em><a href="" onclick="return ShowHashtag(&quot;windows&quot;)">#windows</a><em> </em><a href="" onclick="return ShowHashtag(&quot;network&quot;)">#network</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-108">

      <div class="body details">
6 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message217">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.01.2024 14:17:01 +07">
14:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет! Не в первый раз сталкиваюсь с ситуаций, когда например увольняется девопс-инженер и на его место берут другого. Тут то и начинается цирк с конями. Всё как под копирку.<br><br>Приходит новый девопс-инженер и начинает ныть — ой, мама, какой у вас тут ужас, предыдущий девопс явно был дурак и рукожопая бестолочь. Ну как так можно было делать? Я сейчас все переделаю правильно! Ну и делает. А через год увольняется.<br><br>Следом приходит новый девопс-инженер и начинается — какой кошмар, тут явно обезьяна до меня работала. И так по кругу. Каждый следующий специалист, засирает работу предыдущего и пытается подмять под свою зону комфорта.<br><br><strong>Ну и самый сок.</strong> Беру к себе на парт-тайм девопса, чтобы мою личную инфраструктуру обслуживал. Где крутятся около сотни пет-проектов. Всё отлично, работа прет, задачи пилятся. Но в какой-то момент пытаюсь самостоятельно законектится по ssh на сервак, а оно мне — не, мы тебя не знаем дядя, давай до свидания!<br><br>Хм… задаю вопрос Василию. Василий — а чо меня это, на мой же сервак не пускает? А Василий — а не пустит, у вас там предыдущий девопс такой херни намутил, дурак какой-то, я всё под себя переделал и по уму, бест-практики!<br><br>И да! Теперь авторизация осуществляется через <a href="https://goteleport.com/">Teleport</a>. Но доступ я вам не дам, так как вам там нечего делать, еще сломаете моё детище! Ну и я поднял дополнительный сервер с Teleport, там 20$ лишних в месяц теперь нужно платить…<br><br>Дела… То есть я самостоятельно настроил инфраструктуру, но она никак не вяжется с мировоззрением таких Василиев. Со старой школой намного проще работать, но тоже не всегда. Порой люди прикипают к FTP и SVN и дальше развиваться не хотят, но просят при этом 100500$ в час непонятно за что.<br><br>Это относится ко всем айтишникам. Если пришел в компанию и процессы не совпадают с твоей упитанной зоной комфорта — легаси проект, пайплайны на bash, котики код обоссали и т.п. Не нужно всем об этом кричать и махать руками, какие все козлы.<br><br>Объективно и по полочкам объясни это техдиру. Но в большинстве случаев тебя пошлют нахер и всё останется как было. Потому, что это работает здесь и сейчас и не нуждается в переделке.<br><br>Если что-то хочешь поменять или внедрить, поставь пожалуйста в известность. Не нужно ничего усложнять, чем сложнее инфраструктура, тем больше точек отказа.<br><strong><br>Всегда стремись — упрощать!</strong> Научись адаптироваться, держать баланс и всё у тебя будет в жизни хорошо... <a href = "video_files/sticker (64).webm">😂</a> наверное.<br><br><em>PS: Кстати рекомендую попробовать </em><a href="https://goteleport.com/">Teleport</a><em>, офигительная штука!<br><br>Teleport - это инструмент с открытым исходным кодом для обеспечения доступа к серверам и облачным приложениям с помощью SSH. Он позволяет отказаться от использования VPN, предоставляя единый шлюз для доступа к вычислительной инфраструктуре через SSH, кластерам Kubernetes и облачным приложениям через встроенный прокси.</em><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a> <a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-109">

      <div class="body details">
9 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message218">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="09.01.2024 18:17:19 +07">
18:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Все таки сложно отойти от праздников и заставить себя работать. Придется подключать для разгона «Красный Халат». Погнали.<br><br>Начнем этот спринт с буферов обмена в Linux. Обычно при работе в терминале у нас с тобой есть аж три буфера.<br><br>При правильных манипуляциях, можно воспользоваться всеми тремя.<br><br><strong>Clipboard Buffer</strong><br><br><pre>Копировать : CTRL+SHIFT+C<br>Вставить   : CTRL+SHIFT+V  <br>Вырезать   : CTRL+SHIFT+X  <br>Или контекстное меню</pre><br><br><strong>Primary Buffer</strong><br><br><pre>Копировать : Выделить, копируется само<br>Вставить   : Средняя клавиша мыши</pre><br><br><strong>Application Buffer</strong><br><br><pre>Вставить   : Зависит от приложения<br>Вырезать   : Зависит от приложения<br>Копировать : Зависит от приложения</pre><br><br><strong>Ну а теперь давай потыкаем палкой. Практика.</strong> Заходи в консольку и копируй что-нибудь во все три буфера. В каждый буфер скопируй разный текст, чтобы визуально убедиться.<br><br><strong>Clipboard Buffer</strong><br>Выделяешь и копируешь <strong>CTRL+SHIFT+C</strong><br><br><strong>Primary Buffer</strong><br>Выделаешь, копируется автоматически<br><br><strong>Application Buffer (Оболочка Bash)</strong><br>Курсор в конце строки, вырезаем <strong>CTRL+W</strong><br><br>Так, буферы заполнили. <strong>Очищаем экран: CTRL+L</strong> и начинаем вставлять:<br><br>1. CTRL+SHIFT+V<br>2. Средняя кнопка мыши<br>3. CTRL+Y<br><br>Опа! <strong>Каждый пункт вставляет разный текст.</strong> Ну если конечно ты скопировал разный. В винде немного все иначе, я особо с этим не разбирался. Но 1й и 3й пункт точно работают. А вот средняя кнопка мыши у меня привязана на какую-то фигню с окнами, но не суть.<br><br>Вообще в повседневной работе я обычно использую менеджеры буферов. Потом очень удобно лазить по истории и вставлять необходимое. Сейчас уже не представляю как без них обходиться, например когда нужно скопипастить логин и пароль из разных мест.<br><br>Ладно. Всем легкой недели. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-110">

      <div class="body details">
10 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message220">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="10.01.2024 20:00:35 +07">
20:00
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
День вчера был такой длинный, жаркий, и от начала до конца полная х%йня, каждую минуту. Год как-то стремительно начался в плане объема задач. Привет!<br><br>А жиза заключается в том, что кто-то бездумно пишет говнокод, а кто-то этот говнокод вынужден дебажить. Доказывая что проблема не на сервере, а в кривых руках разработчика.<br><br>Вот и вчера. <strong>Ситуация: </strong>какой-то php скрипт при создании файла на диске, выставляет корявые права на этот файл. Грубо говоря, нужно поставить <strong>777</strong>, а у файла права по факту<strong> 01411.</strong> <strong>Конечно, проблема в сервере!</strong> Пусть дядя Рома с этим разбирается. Ладно, за монету и корку хлеба можно и покопаться.<br><br>Блин, как я давно с php дел не имел. Пришлось вспоминать всю эту лапшу с ООП.<br><br>Так, вдумчиво пробегаюсь глазами по php коду, нахожу функцию, которая ставит права на файл, выглядит это так:<br><br><pre>&lt;?php<br><br>chmod(&apos;test.txt&apos;, &apos;777&apos;);<br><br>?&gt;</pre><br><br>Для простоты восприятия, адаптировал под наши с вами реалии. Вроде всё корректно, тошноты пока нет. Чо этой собаке надо? Запускаю скрипт, хм… снова получаю вместо <strong>777</strong> какую-то фигню<strong> 01411.</strong><br><br>А если уберем кавычки? Вдруг это как string воспринимается:<br><br><pre>&lt;?php<br><br>chmod(&apos;test.txt&apos;, 777);<br><br>?&gt;</pre><br><br>Метод тыка не помог, но терпим до последнего. В документацию по chmod в php не лезем. <strong>Нас же НЕ просили исправить баг, нас поставили перед фактом — проблемы на сервере.</strong> Вот мы и пытаемся доказать обратное.<br><br><strong>Расчехляем strace</strong><br><br><pre>strace php app.php</pre><br><br>В самом конце видим:<br><br><pre>read(3, &quot;&lt;?php\n\nchmod(&apos;test.txt&apos;, 777);\n\n&quot;..., 4096) = 35<br>chmod(&quot;test.txt&quot;, 01411) = 0</pre><br><br><strong>Видим знакомое 01411</strong>. Доказательства собрали.<strong> С серверами всё хорошо</strong>, на лицо баг в коде. Несем эту информацию тимлиду, пусть учит разработчика читать документацию и дает ему по шапке.<br><br><strong>А что все-таки не так с php скриптом, почему 01411?</strong> Вообще это не наше дело. Но если коротко:<br><br>В php целые числа могут быть указаны в десятичной, шестнадцатеричной, восьмеричной или двоичной системе. <strong>Все это дело должно обозначаться начальным нулем. </strong>Наша тема - восьмеричная система. Если перевести 777 в восьмеричную систему получим как раз 1411. <br><br><a href = "stickers/sticker (25).webp">📌</a>А откуда берется 01 перед 1411?? А давай ты сам подумаешь и в комментариях напишешь. А мы тебе дружно лайк поставим.<br><br>Ошибка была в том, что в php скрипте число 777 передается как строка. Неважно в скобках оно или нет.<br><br>Фикс тут простой, просто вставляем <strong>0</strong> перед <strong>777:</strong><br><br><pre>&lt;?php<br><br>chmod(&apos;test.txt&apos;, 0777);<br><br>?&gt;</pre><br><br>Ну а если хочется без ведущего нуля, то так:<br><br><pre>&lt;?php<br><br>chmod(&apos;test.txt&apos;, intval(&apos;777&apos;, 8));<br><br>?&gt;</pre><br><br>Вот такие пироги. Можно было бы продолжить метод тыка и вставить сразу <strong>0</strong> перед <strong>777</strong>, <strong>но повторюсь — нас не просили ничего багфиксить.</strong> Не нужно упрощать кому-то работу, это опыт, который ты воруешь у человека. <br><br>Пусть лучше лишние полчаса погуглит, посмотрит, зато самостоятельно заполнит свою дофаминоваю яму. И потешет ЭГО новой победой над багом.<br><br>Ладно, увидимся, давай!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em> </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-111">

      <div class="body details">
13 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message221">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="13.01.2024 17:12:20 +07">
17:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, далеко ходить не будем, сегодня более интересный <strong>кейс с отладкой php-fpm который непонятным образом, рандомно вставал раком.</strong> Да, будем использовать наш любимый strace, как ты любишь.<br><br><strong>Проблема:</strong> На сервере крутится php-fpm, в любой момент времени процесс начинает зависать, то есть перестаёт обрабатывать любые запросы.<br><br>В какой-то момент может очухаться, а может и нет. В любом случае проблема решается перезапуском <code>systemctl restart php-fpm</code>. Ну и в логах ничего криминального нет, даже в дебаг режиме. По факту имеем пятьсот две плохих шлюхи (502 Bad Gateway).<br><br>Ребята придумали костыль, какой-то башник, который в кроне проверяет зависание и затем автоматически ребутит. Да, как временное решение подходит. Но сам знаешь, что временное всегда становится постоянным.<br><br><em>До этого были перепробованы все возможные варианты с конфигом, накручивание буферов, гугление, даже грешили на nginx, но ничего не помогало.</em><br><br>Так и жили пока дядя Рома не соизволил разобраться в ситуации, ну и разобрался.<br><br><strong>Расчехляем strace</strong><br><br>Для начала ты должен знать, что php использует модель master/slave. Главный процесс использует воркеры (workers) для обработки входящих запросов. Запрос может выполниться на любом из воркеров, поэтому нужно сказать strace чтобы мониторил все воркеры. Для этого будем использовать связку с командой pidof ну и приправим это sed’ом.<br><br><pre>strace -f $(pidof php-fpm | sed &apos;s/\([0-9]*\)/\-p \1/g&apos;) -epoll</pre><br><br>Sed обрезает лишнюю херню и оставляет только pid в голом виде, ну и затем эти пиды закидываем в strace.<br><br>А после запуска команды и зависания php, я увидел такое:<br><br><pre>[pid 1234] poll([{fd=10 ...]) = 0 (Timeout)<br>[pid 1234] poll([{fd=10 ...]) = 0 (Timeout)<br>[pid 1234] poll([{fd=10 ...]) = 0 (Timeout)<br>[pid 1234] poll([{fd=10 ...]) = 0 (Timeout)</pre><br><br>Ага, уже есть с чем работать. Какой-то таймаут. И файловый дескриптор fd=10. Хм. Теперь надо понять, что это за таймаут и дескриптор fd=10. Для этого сделаем так:<br><br><pre>lsof -p 1234</pre><br><br>Эта команда выдаст список всех файлов, которые открыты процессом, включая сокеты.<br><br><pre>php 0u IPv4 13193 0t0 TCP :8000 (LISTEN)<br>php 1u CHR 1,4 0t0 4728 /dev/null<br>php 2u CHR 1,4 0t0  4728 /dev/null<br>php 3ur REG /tmp/.RedPem.Hte (deleted)<br>php 4u IPv4 TCP :8000-&gt;:5042 (ESTABLISHED)<br>php 5uW REG sessions/sess_tmh0dls75<br>php 6u 0000 0,9 0 4842 anon_inode<br>php 7u unix 0t0 25714 socket<br>php 8u unix 0t0 25714 socket<br>php 9u TCP l-&gt;l:11210 (ESTABLISHED)<br>php 10u TCP host-&gt;10.0.0.100:9200 (SYN_SENT)</pre><br><br>Смотрим самую последнюю строку как раз с fd=10. Видим что у нас проблема с подключением к <code>10.0.0.100:9200</code>. Очень интересно. Что это вообще за айпишник такой.<br><br><strong>Не останавливаемся и копаем дальше.</strong><br><br>В большинстве случае порт 9200 принадлежит ElasticSearch. Роем в эту сторону и обнаруживаем, что в php проекте используется библиотека ElasticSearch PHP.<br><br>Как оказалось, при разработке проекта, прекрасные девы подключили ElasticSearch, чтобы чото там отлавливать. А на айпишнике <code>10.0.0.100</code> как раз располагалась серверная часть ElasticSearch. Разработку прекратили, сервер с эластиком убили, но из конфигов проекта забыли выкосить.<br><br>Вот оно и продолжало ломиться туда, где ничего нет. В этом и заключался баг. PHP постоянно опрашивал ElasticSearch сервер для получения ответа, но в ответ получал хуй с маслом. Рабочий процесс зависал в цикле и не мог ответить ни на один другой запрос.<br><br>Такие дела. Я прям уверен — если пройтись с помощью strace по всяким популярным php движкам, там столько дерьма вылезет. Кстати с помощью strace можно вполне удачно разгонять проекты, банально фиксишь то, что вызывает таймауты.<br><br>Порой наталкивался на ситуацию когда проект тормозил из-за корявого резолва доменов, или были проблемы с таймзоной, аналогично всё это дебажилось через strace.<br><br>В общем изучай и бери на вооружение, опыт полезный. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em> </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-112">

      <div class="body details">
15 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message223">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="15.01.2024 18:16:21 +07">
18:16
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем привет. Пока тут боролся с багом, решил поделиться и с вами. Сегодня рассмотрим <strong>как без curl/wget/telnet делать tcp/udp запросы</strong>. Опять же мало кто про это знает.<br><br>Порой бывает что на серверах нет курла, вегета (как приправа с упоротым поваром) и даже пинга. Например в docker контейнерах. И установить никак. Но в bash скрипте или во время дебага надо протестировать приложение, службу или порт.<br><br>В общем если столкнулся с отсутствием привычных тебе утилит, выход есть. Сейчас покажу крутые фичи.<br><br><em>Я обычно при дебаге использую telnet, чтобы проверить открыт ли нужный порт на удаленной тачке. Чтобы понимать, что никакой фаервол меня не блокирует.</em> <em>Почему telnet? Привычка!</em><br><br><strong>Проверяем открыт ли порт 80 и 443:</strong><br><br><pre>:&gt; /dev/tcp/bashdayz.ru/80<br>:&gt; /dev/tcp/bashdayz.ru/443</pre><br><br>Если порт открыт, то после выполнения команды на экран ничего не выведется. Но ты в праве получить статус через<code> echo $?</code>. Если вернулся 0 значит порт открыт и все ок. Если вернулось &gt; 0, то пизда рулю, порт закрыт.<br><br>Есть нюанс, команда может висеть очень долго, поэтому приправляем ее таймаутом:<br><br><pre>timeout 5s bash -c &apos;:&gt; /dev/tcp/bashdayz.ru/80&apos;<br>timeout 5s bash -c &apos;:&gt; /dev/tcp/bashdayz.ru/443&apos;</pre><br><br>Теперь в случае если порт не доступен, мне не нужно ждать 100500 часов пока команда завершится. Все станет известно спустя 5 секунд. Повторюсь, что на экран никакого вывода не будет. Статус получаем через <code>echo $?</code>, ну ты понял.<br><br><strong>А что означает этот непонятный символ «:&gt;»?</strong><br><br>Нет, это не смайлик с дятлом. Это сокращенная версия true:<br><br><pre>true &gt; /dev/tcp/bashdayz.ru/80</pre><br><br><em>true - команда, которая всегда возвращает успешный (нулевой) код возврата. Это означает, что команда завершилась успешно, без ошибок.</em><br><br>Чтобы весь этот фокус работал, требуется bash с поддержкой net-redirections (--enable-net-redirections), но как показывает практика такая функция в 99% включена по умолчанию, если конечно ты не адепт gentoo и из исходников bash собирал.<br><br><strong>Аналогично можно слать udp запросы:</strong><br><br><pre>:&gt; /dev/udp/localhost/8888</pre><br><br>То есть синтаксис простой: <strong>/dev/протокол/хост/порт</strong><br><br>Давай еще пример покажу как с NIST Time Server получить актуальную дату и время с разных NTP:<br><br><pre>cat &lt;/dev/tcp/time.nist.gov/13<br>cat &lt;/dev/tcp/time.cloudflare.com/13<br>cat &lt;/dev/tcp/time.windows.com/13<br>cat &lt;/dev/tcp/pool.ntp.org/13<br>cat &lt;/dev/tcp/time.google.com/13<br>cat &lt;/dev/tcp/time.apple.com/13<br>cat &lt;/dev/tcp/time.nrc.ca/13<br>cat &lt;/dev/tcp/time.windows.com/13</pre><br><br>Некоторые могут не работать, санкции или хрен пойми че с ними, но первый у меня везде работает.<br><br>Ну и как дополнительный вариант для проверки открытых портов, можно использовать <strong>nc</strong>.<br><br><pre>nc -zv bashdayz.ru 80</pre><br><br>Тут оно на экран тебе результат сразу вывалит без всяких костылей.<br><br><em>nc или netcat - утилита, которая предоставляет возможность взаимодействия с сетью. Она может выполнять различные функции, такие как установка TCP или UDP соединений, передача данных между хостами, сканирование портов, создание простых серверов и т.п.</em><br><br>Ключ <strong>-z</strong> тестирует порт без передачи данных, а ключ <strong>-v</strong> логично что verbose (подробная инфа).<br><br>Да, ты скажешь можно же через <strong>nmap</strong> это все сделать, да, справедливо. Но я показываю как не пользоваться сторонними утилитами и получить желаемое с помощью bash. Пардон за <strong>nc</strong>, но не мог его не упомянуть.<br><br>Пользуйся, обязательно пригодится в работе и дебаге. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-113">

      <div class="body details">
16 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message224">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.01.2024 19:18:43 +07">
19:18
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Вчера в моём <a href="https://dzen.ru/bashdays?tab=articles">ДЗЕНе</a> задали вопрос - Роман, а<strong> как скачать файл не имея под рукой curl/wget, а прям средствами bash</strong>? Видимо придется <a href="https://t.me/bashdays/223">тему</a> продолжить. Сегодня рассмотрим как такое осуществить.<br><br>Есть у меня файл который лежит <a href="http://files.bashdayz.ru/files/test.zip">тут</a>. Нам нужно его как-то хитро скачать. Будем использовать сокеты.<br><br><strong>Накидываем скрипт</strong><br><br><pre>#!/bin/bash<br><br>host=&quot;files.bashdayz.ru&quot;<br>port=&quot;80&quot;<br>path=&quot;/files/test.zip&quot;<br><br>request=&quot;GET $path HTTP/1.1<br>Host: $host<br>Connection: close&quot;<br><br>exec 3&lt;&gt;/dev/tcp/$host/$port<br>echo -e &quot;$request&quot; &gt;&amp;3<br>cat &lt;&amp;3 &gt; test.zip<br>exec 3&gt;&amp;-<br><br>echo &quot;Success&quot;</pre><br><br><strong>Тут все просто:</strong><br><br>1. Задаем переменные, хост, порт, путь до файла<br>2. Проставляем необходимые заголовки для запроса<br>3. Ну и собственно скачиваем файл на диск<br><br>Теперь разберем третий пункт подробнее. С виду какой-то ужас, но не ссы, ща расскажу.<br><br>В первой строчке открывается файловый дескриптор с индексом 3 для чтения и записи данных через TCP-соединение + хост + порт. <br><br>Во второй строчке отправляем HTTP запрос на сервер через открытое соединение с дескриптором 3. Включаем в него GET запрос и необходимые заголовки.<br><br>В третьей строчке читаем данные из файлового дескриптора 3 в cat, который связан с соединением сервера и записываем их в файл. <br><br>Последняя строка закрывает файловый дескриптор 3 (сокет) после завершения операции чтения данных. Можно не закрывать и оставить портал в ад открытым.<br><br><strong>Ну и все. Файл скачали, получили Success!</strong><br><br>Почему я выбрал файловый дескриптор с индексом 3? Ну вообще 0 = stdin, 1 = stdout, 2 = stderr. Короче 0, 1, 2 зарезервированы, а я просто взял следующий.<br><br>Но вообще в манах bash рекомендуют быть осторожным в использовании дескрипторов больше 9ти. Так как возможен конфликт с дескрипторами, которые используются внутри оболочки.<br><br><em>К сожалению для https такое провернуть не получится, возникнут проблемы. Прямой обмен данными через сокеты не предусматривают обработку SSL/TLS.</em><br><br>Такие дела, вряд ли ты это будешь где-то применять. Но обладая такими знаниями, ты постигаешь то, чего никогда не постигнут другие.<br><br>В общем не болей, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message225">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.01.2024 22:18:40 +07">
22:18
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_28@16-01-2024_22-18-40.jpg">

         <img class="photo" src="photos/photo_28@16-01-2024_22-18-40_thumb.jpg" style="width: 260px; height: 241px"/>

        </a>

       </div>

       <div class="text">
Я тут выше заикнулся про Дзен. Ну дак вот, если у тебя есть учетка в Яндексе или ВК,<strong> буду безумно рад если поддержишь мои начинания</strong> и нажмешь кнопку - <a href="https://dzen.ru/bashdays?tab=articles">подписаться.</a> Не обязательно его потом там читать, всё самое сочное всегда будет тут. А я тебе котиков, лайк и интересного чтива!<br><br>Да, там есть цензура. Приходится контент немного адаптировать. Неприличного авторского слога и игр с летающими Bash письками<a href="https://t.me/bashdays/208">,</a> там уже не найдешь. <a href = "stickers/AnimatedSticker (10).tgs">👨‍🦲</a> Все по взрослому.<br><br><em>Ну и в конце февраля-марте запланировал пилотный запуск моих бесплатных видео-уроков на тему Advanced Bash Scripting + Debug Factory. С задачками, домашними заданиями и экзаменами. Пока пробую снимать, нихрена не получается, но сделаю всё возможное. Запуск будет именно в Дзене, а дальше уже посмотрим, как пойдет.</em><br><br>В общем заранее всем спасибо, всем краба, всем обнимашек!
       </div>

       <div class="signature details">
ʜ ᴅ
       </div>

      </div>

     </div>

     <div class="message service" id="message-114">

      <div class="body details">
18 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message226">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.01.2024 14:16:06 +07">
14:16
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Порой из консоли необходимо быстренько узнать свой внешний айпишник. Например, накрутил какой-нибудь VPN, а графической оболочки нет, чтобы зайти на сайт и визуально глянуть где сегодня находится моя жопа.<br><br>Да и в bash скриптах иногда хочется без длинных команд и тонны кода обойтись. Короче как говорит, все уже придумано за нас. А если еще и алиасы накрутить, вай вай, пэрсик.<br><br>Я пользуюсь двумя сервисами:<br><br><pre>curl ifconfig.me<br>curl geofind.me</pre><br><br>Первый выдаст чисто айпишник, который ты сможешь загнать в переменную и потом его использовать.<br><br>Второй помимо айпишника, вычислит местоположение.<br><br><pre>94.227.165.240<br>Aeza International Ltd<br>Ulitsa Pushkina, Dom Kolotushkina, Austria</pre><br><br>Второй вариант использую намного реже. Так как привык всё усложнять, сначала получаю ip через <code>ifconfig.me</code>, а потом уже через <code>whois &lt;ip&gt;</code>.<br><br>Подобных сервисов полно, я показал чем пользуюсь сам. <br><br><strong>Альтернативы:</strong><br><br><pre>curl ipinfo.io/ip<br>curl ipecho.net/plain<br>curl icanhazip.com<br>curl ident.me<br>curl api64.ipify.org<br>curl api.ip.sb/ip<br>curl ipv4.wtfismyip.com/text<br>curl ip2location.io/ip<br>curl checkip.amazonaws.com</pre><br><br><strong>С дополнительной инфой:</strong><br><br><pre>curl ip-api.com/line<br>curl ipinfo.io<br>curl api.myip.com<br>curl &apos;api.ipregistry.co/?key=tryout&apos;</pre><br><br>В списке с «дополнительной инфой» есть сервисы которые прям богатый JSON выплёвывают, потыкай.<br><br><em>Я раньше обладал безлимитным API ключом для MaxMind, вот там да, был полный фарш. Можно было по IP узнавать вплоть до названия организации. Даже софтину в бородатые 2000е писал, которая пользовалась популярностью у пентестеров.</em><br><br>Но если у тебя есть ключик, узнать свой айпишник можешь через команду:<br><br><pre>curl -H &quot;Authorization: KEY&quot; https://geoip.maxmind.com/geoip/v2.1/city/me</pre><br><br>Ааа, еще вариант с дигом есть, но оно длинное:<br><br><pre>dig +short myip.opendns.com @resolver1.opendns.com</pre><br><br><strong>Есть и минусы</strong>. Результат зависит от доступности сервисов. Если сервис выплюнет соплю &gt; 200, увы все поломается.<br><br>Поэтому если используешь это в bash скриптах, советую добавлять сервисы в массив пачкой и делать ротацию. Если один выдал соплю, брать информацию с другого. В принципе это бест-практики в любых алгоритмах для отказоустойчивых систем.<br><br>Ладно, сегодня еще увидимся, далеко не уходи. Хорошего дня!<br><br><em>PS: Да, всем спасибище, лайк и котиков</em><em>🐾</em><em> </em><em>🤩</em><em>🥳</em><em>🥰</em><em>🫥</em><em> кто </em><a href="https://t.me/bashdays/225">тыкнул</a><em> на кнопочку в дзене! Вы супер, обнял!</em><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message228">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="18.01.2024 20:07:37 +07">
20:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_29@18-01-2024_20-07-37.jpg">

         <img class="photo" src="photos/photo_29@18-01-2024_20-07-37_thumb.jpg" style="width: 260px; height: 198px"/>

        </a>

       </div>

       <div class="text">
Поднимал тут у себя огородик с wg-easy, всё ок. Но из коробки, морда для создания ключей работает по протоколу http. Вроде ничего страшного, но не серьезно. Ну и настраивать <code>nginx + acme.sh</code> тоже капец лень.<br><br>Пока искал готовое решение (кстати <a href="https://github.com/wg-easy/wg-easy/wiki/Using-WireGuard-Easy-with-nginx-SSL">нашел</a> нативный мануал от wg-easy), набрел на интересную штуку. <strong>Называется Nginx Proxy Manager.</strong><br><br>Короче это морда для nginx, чтобы не руками конфиг задрачивать, а мышкой галочки натыкивать + из коробки нативная интеграция с letsencrypt.<br><br><em>Возможно у нас в </em><a href="https://t.me/bashday">чатике</a><em> где-то это уже и пролетало, но я не видал.</em><br><br>Поднимается за минуту через docker-compose, без лишних велосипедов и костылей. Дружит с sqlite и mysql. Есть система распределения прав, каждый юзер может редактировать свои локейшены и хосты. Поддерживает малину и arm архитектуры. Ну и естественно есть гибкий Access List и Basic Auth.<br><br><strong>Киллер-фича:</strong> Можно генерить wildcard ssl, выбираешь из большого выпадающего списка к примеру cloudflare и оно тебе DNS Challenge делает. Это прям порадовало.<br><br>Понятно дело, что оно не максимально гибкое в плане конфигурации через морду. Но для этого есть дырка, чтобы вставлять свои куски конфига в текстовом формате. А так базового функционала прям за глаза.<br><br>В общем рекомендую как для локальной разработки, так и для каких-то своих сервисов вроде bitwarden и т.п.<br><br>Картинки у них на сайте посмотрите, не буду сюда запихивать.<br><br><a href = "stickers/AnimatedSticker (11).tgs">🌐</a> <a href="https://nginxproxymanager.com/">https://nginxproxymanager.com/</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a><em> </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-115">

      <div class="body details">
21 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message229">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.01.2024 15:17:01 +07">
15:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Глазом не успел моргнуть как выходные вылетели в трубу. Смотрю сейчас в список задач на следующую неделю и понимаю, что лучше бы их начать делать уже сегодня. <br><br>Ладно, это детали. Сегодня покажу <strong>как узнать пароль пользователя, который подключается к серверу по ssh.</strong> Менять пароль я не буду, это не тру вэй. Я воспользуюсь своим любимым strace.<br><br><strong>Вообще самый простой вариант: </strong>Пишешь пользователю - скажи мне свой пароль, мне нужно кое-что проверить. Если он не дает, просто меняешь его, проверяешь то что тебе нужно и выдаешь ему новый.<br><br>Но это актуально для корпоративных систем, когда ты root на сервере, а не кладовщица в обувном магазине.<br><br><strong>Короче идем рутом на сервер и расчехляем strace</strong><br><br><pre>strace -f -p $(pgrep -o sshd) -o /tmp/passwd.txt -v -e trace=write -s 64</pre><br><br>Запускаем и собираем урожай в файл passwd.txt. Работает так:<br><br>1. -f = следим за всеми процессами sshd (мастер и дочерние)<br>2. -p = ищем все PID sshd процессов<br>3. -o = файл куда пишем результаты<br>4. -v = пишем подробности<br>5. -e = триггеримся только на запись данных<br>6. -s = ограничиваем вывод данных 64 байтами (меньше мусора)<br><br>Теперь, когда какой-нибудь пользователь авторизуется на сервере по ssh, в файл passwd.txt в открытом виде будет записан его актуальный пароль.<br><br>Выглядит это так:<br><br><pre>1088 write(5,&quot;\0\0\0\5oleg&quot;, 9) = 9<br>1088 write(5, &quot;\0\0\0\Barmaley1982&quot;, 17) = 17</pre><br><br>Логин oleg, пароль Barmaley1982. Дело в шляпе. Этакий сниффер на коленке с помощью коробочных инструментов. Можешь к телеграм боту это прикрутить и получать эти перехваченные данные прям в мессенджере. Как это сделать<a href="https://t.me/bashdays/122"> писал тут</a>.<br><br>Кстати этим кейсом очень часто пользуются блэкхеты и пентестеры, которые через дыру получают рута и затем втихую проворачивают свои делишки оставаясь в тени.<br><br>Такие дела. Ну и как там пишут:<br><br><em>Прошу отметить, что предоставленная здесь информация предназначена исключительно для образовательных и информационных целей. Я не призываю и не одобряю незаконные действия, и использование этой информации для незаконных целей запрещено. Читатели должны соблюдать законы своей страны и использовать свои навыки с уважением к этическим нормам и законам.</em><br><br>Давай, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em> </em><a href="" onclick="return ShowHashtag(&quot;security&quot;)">#security</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-116">

      <div class="body details">
23 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message232">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.01.2024 17:12:05 +07">
17:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Сегодня покажу <strong>как на wsl хитро вкорячить свежую версию ubuntu 23 или 24.</strong> Так как в коробке идет только старенькая 22, придется немного потыкать в консольке.<br><br><strong>Зачем это нужно?</strong> Ну например проверить какие-то штуки, которых нет в ubuntu 22. А для чего мне это понадобилось, я напишу в следующем посте, как раз одно на другое наложилось.<strong> Если спойлернуть:</strong> писал пост про софтину, но она работает только с новыми версиями убунты. Вот и пришлось немного переобуться.<br><br><strong>По bash версиям имеем такое:</strong><br><br><blockquote>22.04 - 5.1.16<br>23.04 - 5.2.16<br>24.04 - 5.2.21</blockquote><br><br>Так, есть несколько способов вкорячить свежую убунту в wsl.<br><br><strong>Хитрожопый способ с docker</strong><br><br>Заходим в wsl убунты 22 и ставим docker если он у тебя еще не стоит. <br><br><pre>curl -sSL https://get.docker.com | sh<br>usermod -aG docker $(whoami)</pre><br><br><em>WSL DETECTED: We recommend using Docker Desktop for Windows.</em><br><br>Оно грязно выругается, но ждем 20 секунд и установка завершиться успехом<br><br>Перезапускаем сессию чтобы пользователь смог работать с docker.<br><br>Дальше тащим образ ubuntu:lunar, как раз это версия 23.04. Аналогично можешь и другие версии/разновидности дистрибутива на wsl вкорячивать. Все что есть в docker можно поднять в wsl.<br><br><pre>docker pull ubuntu:lunar</pre><br><br>Запускаем контейнер и выходим из него<br><br><pre>docker run -it --name ubuntu23 ubuntu:lunar<br>exit</pre><br><br>Проверяем что контейнер есть:<br><br><pre>docker ps -a</pre><br><br>Экспортируем<br><br><pre>docker export ubuntu23 &gt; /tmp/ubuntu23.tar</pre><br><br>В папке <a href="" onclick="return ShowBotCommand(&quot;tmp&quot;)">/tmp</a> появился tar размером где-то 75 мегабайт. Уже хорошо. Теперь на хостовой с виндой создаем папку. Я сделал ее на диске <strong>D:</strong> и назвал так <code>D:\\wsl\\ubuntu23</code><br><br>Теперь копируем этот tar на хостовую машину с виндой в папку <code>D:\\wsl\\ubuntu23. </code><br><br>Переходим в powershell и импортируем tar:<br><br><pre>wsl --import ubuntu23 D:\wsl\ubuntu23\ D:\wsl\ubuntu23\ubuntu23.tar</pre><br><br>В папке <code>D:\\wsl\\ubuntu23</code> появится новый файл: ext4.vhdx размером около 150 мегабайт. Так, дальше…<br><br>Смотрим что у нас есть, в powershell:<br><br><pre>wsl -l -v</pre><br><br>На экран вываливается примерно такое:<br><br><pre>PS C:\Users\user&gt; wsl -l -v<br><br>  NAME            STATE       VERSION<br>* Ubuntu-22.04    Running        2<br>  ubuntu23        Stopped        2</pre><br><br>Собственно на этом всё. Запускаем lunar:<br><br><pre>wsl -d ubuntu23</pre><br><br>Всё!<br><br><strong>Второй способ. </strong>Сделать dist-upgrade уже существующей убунты:<br><br><pre>sudo sed &apos;s/lts/normal/g&apos; /etc/update-manager/release-upgrades<br>sudo sed -i `s/jammy/lunar/g` /etc/apt/sources.list<br>sudo apt update<br>sudo apt upgrade<br>sudo apt dist-upgrade</pre><br><br>Хотя апргрейд крайняя мера, когда 22.04 уже не нужна. А мне нужна! Пока не знаю зачем, но пусть будет.<br><br><strong>Третий и самый простой.</strong><br><br>Поставить Ubuntu (Preview) по <a href="https://apps.microsoft.com/detail/9P7BDVKVNXZ6">этой ссылке</a> прям с магазина микрософта. Кликнул и последняя убунта у тебя в wsl.<br><br>В моём случае сразу прилетел Release: 24.04 Codename: noble. Через docker конечно интереснее, есть какая-то прозрачность и контроль.<br><br>А так, как я ленивая жопа, я предпочел поставить Ubuntu Preview. Но способ с docker я конечно пощупал и поставил 23 версию. Теперь имею зоопарк 22, 23, 24, думаю для экспериментов вполне хватит.<br><br><em>Да, когда ставишь через docker, оно автоматически пропишется в Windows Terminal и потом всю эту кухню можно запускать кликом мыши, без ввода wsl -d.</em><br><br>Вот и все. Чуть позже закину пост как раз про ту самую софтину, которая хочет работать только на свежих линуксах. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;windows&quot;)">#windows</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message233">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="23.01.2024 20:31:20 +07">
20:31
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Ладно, хорош про винду, ловите еще чтива. Выше в <a href="https://t.me/bashdays/232">посте</a> когда ставил docker, вылез алерт «WSL DETECTED: We recommend using Docker Desktop for Windows.» <br><br>Меня заинтересовал таймер обратного отсчета, который выводился на экране, мол через 20 секунд всё будет ок. Цифры менялись затирая предыдущие, но с нюансом, оставался ведущий ноль.<br><br>Ну и чот захотелось на Bash’е такое запилить, ну и запилил:<br><br><pre>#!/bin/bash<br><br>msg=&quot;deadline in: &quot;<br>row=2<br>col=2<br><br>clear<br>tput cup $row $col<br>echo -n &quot;$msg&quot;<br>tput civis<br><br>l=${#msg}<br>l=$(( l + col ))<br><br>for i in {10..01}<br>do<br>    tput cup $row $l<br>    echo -n &quot;$i&quot;<br>    sleep 1<br>done<br><br>tput cnorm</pre><br><br>Запускаем, еее! Пошел отсчет от 10 до 01 с ведущим нулем. Прекрасно!<br><br><strong>Из непонятного, рассказываю:</strong><br><br>1. <code>tput cup $row $col</code> = ставим курсор в нужную позицию<br>2. <code>tput civis</code> - скрываем курсор<br>3. <code>l=${#msg}</code> - вычисляем длину сроки msg<br>4. <code>l=$(( l + col ))</code> - позиция вывода таймера<br>5. <code>tput cup $row $l</code> - кидаем курсор в позицию таймера<br>6. <code>tput cnorm</code> - включаем курсор обратно<br><br><strong>Вариант без ведущего нуля</strong>:<br><br><pre>#!/bin/bash<br><br>seconds=10<br><br>for ((i=seconds; i&gt;=1; i--))<br>do<br>    echo -ne &quot;deadline in: $i \033[0K\r&quot;<br>    sleep 1<br>done<br><br>echo -e &quot;\nFuck up!&quot;</pre><br><br><em>Но этот вариант мне не нравится, нет в нем искры, если жать Enter, то таймер перескакивает на новую строку, ну и ведущего нуля нет, фу.</em><br><br>Вот такая игрушка у меня получилась. Возможно где-нибудь и воткну потом эту поделку, попугать коллег на продакшене. Пусть не расслабляются, запуская бездумно Bash скрипты. Надо еще клавиатуру блокировать. Чем бы дитя не тешилось.<br><br>Ладно, кидай в комментарии свои варианты, заценим!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-117">

      <div class="body details">
24 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message235">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="24.01.2024 17:11:55 +07">
17:11
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Я тут чет плотно подсел на игрушку Metroid, вроде обычная бродилка, но прям какая-то атмосферная. Прохожу сейчас по вечерам Zero Mission на GBA, ну как прохожу, брожу по карте и в дырки тыкаюсь. Хоть немного отвлекает от рутины.<br><br>Давай по теме. Ща будет интересно. Смотри, когда ты выполняешь команду <strong>ls -l,</strong> оно выводит тебе на экран список каталогов и файлов. Все это цветное и красивое. Но если сделать так:<br><br><pre>ls -l | cat</pre><br><br>То по итогу получим просто список каталогов и файлов, без навешанных стилей и красок. Серое и унылое. Куда делись управляющие символы (последовательности), которые всё это раскрашивают?<br><br>Да, есть такое. Когда применяешь перенаправленный вывод, управляющие символы куда-то исчезают. Давай разберемся что происходит.<br><br>Все предельно просто. В утилитах содержится проверка своего стандартного вывода (stdout), которая не использует некоторые управляющие символы, если stdout не связан с терминалом.<br><br>И это вполне логично. Если бы эти управляющие символы передавались следующей команде, в моем случае в cat. То cat бы получил на вход помимо данных, кучу мусора, типа такого:<br><br><pre>\e[31mBashdays\e[0m</pre><br><br><strong>Теперь полезем в кишки, чтобы лучше понять происходящее.</strong><br><br>Запускаем strace:<br><br><pre>strace -o output.txt -yf ls -l --color=auto | cat</pre><br><br>Тут я указал утилите <strong>ls</strong> опцию <strong>color</strong> с аргументом <strong>auto</strong>. В большинстве случаев из коробки идет <strong>alias</strong> в котором уже прописана эта опция. Но так, как мы запускаем<strong> ls</strong> через <strong>strace</strong>, то существующие алиасы не будут использоваться. Вот лишь по этому и запихиваем все это в одну строку.<br><br><strong>-y =</strong> отслеживать открытие файлов.<br><strong>-f =</strong> отслеживать все процессы и форки.<br><strong>-o =</strong> пишем выхлоп strace в файл.<br><br>Открываем файл output.txt и смотрим в него пустым взглядом. Но лучше грепаем вызов ioctl:<br><br><pre>grep -i &quot;ioctl&quot; output.txt</pre><br><br>Получаем несколько строк, в которых видим ошибку:<br><br><pre>-1 ENOTTY (Inappropriate ioctl for device)</pre><br><br>Это говорит о том, что процесс попытался выполнить операцию ввода-вывода (I/O), которая не поддерживается устройством. Канал просто не поддерживает эту возможность.<br><br>Ну и напоследок сделаем инъекцию. В <a href="https://t.me/bashdays/109">этом посте</a> можешь еще один пример с инъекцией глянуть. Запускаем:<br><br><pre>strace -o /dev/null -fe inject=ioctl:retval=0 ls -l --color=auto | cat -v</pre><br><br>Суть такая, если возникает ошибка, то ничего не делаем, а продолжаем работу. Эмулируем ситуацию, когда <strong>ioctl</strong> вернул статус успеха, а не <strong>-1 ENOTTY.</strong><br><br>Опция <strong>retval=значение</strong>, это своего рода фильтр, в моем контексте он будет трассировать только системные вызовы <strong>ioctl</strong> у которых статус = не успех.<br><br>Запустили. Команда отработала, на экране видим список каталогов и файлов с управляющими символами (последовательностями).<br><br><pre>drwxr-xr-x ^[[0m^[[01;34m1^[[0m<br>-rwxr-xr-x ^[[01;32mbash^[[0m<br>drwxr-xr-x ^[[01;34mbin^[[0m<br>drwxr-xr-x ^[[01;34mnginx^[[0m</pre><br><br>Что и следовало доказать. Ну а если просто хочется протестировать управляющие символы без всяких strace, можно воспользоваться аргументом <strong>always</strong> и ключом <strong>-v</strong> для <strong>cat</strong>.<br><br><pre>ls --color=always | cat -v</pre><br><br><strong>-v, --show-nonprinting</strong><br><br>Вот так вот и живем. Теперь и ты это знаешь. На выходные обещаю уйти в режим тишины, чтобы вам не надоедать своими сумасшедшими исследованиями. Хорошего всем дня, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-118">

      <div class="body details">
25 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message237">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="25.01.2024 21:27:08 +07">
21:27
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сегодня вынужденно весь день работал инженером электроником. Три компьютера собрал, винду накатил, дату перенес, господи, как это выматывает. Я лучше ELK лишний раз настрою, чем всё это железо разгребать, стар я для этого дерьма стал.<br><br>Ну и тут одно событие как-то вскользь прошло и связано оно с нативным файловым менеджером «FAR» который теперь можно без лишнего геморроя поставить на новые линуксы прям из официального репозитория.<br><br>Да, когда я начинал свой путь в айти, FAR был как правая рука для окошечников. Все активно призывали пересесть на total commander, но сколько я не делал попыток, так и не смог себя пересилить. Ну люблю я  все эти консольные штуки и минимализм. <br><br><em>У меня знакомый большую часть жизни вообще в FAR фронтенд делал, плагинами обвешал и получилась неплохая IDE.</em><br><br>А вот когда я начал знакомство с linux, то второе, что я запустил (после vi), это был как раз midnight commander. Ну и все. FAR и mc стали маст-хэв штуками. Вот даже сейчас сидя на винде у меня вкорячен FAR и я даже раза два в месяц им пользуюсь.<br><br>Мой роадмеп был такой - Norton commander → Dos navigator → FAR → Midnight commander.<br><br>Короче в новых убунтах ставится так:<br><br><pre>sudo apt install far2l</pre><br><br>Кому подойдет FAR? Все просто, тому, кому не нравится midnight commander. <br><br>Я попробовал ради прикола воткнуть его на 23ю убунту (в wsl), взлетело, выглядит как FAR, даже alt+f1 работает для выбора дисков. Ну и по ssh запускается, в смысле подключаешься к серверу по ssh и запускаешь там FAR, работает.<br><br>Не знаю, но я уже точно ни на что не променяю Midnight commander. Даже в винде его использую. Мы связаны одной цепью.<br><br>А какой у тебя был путь с файловыми менеджерами? Чем нынче пользуешь?<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;рабочиебудни&quot;)">#рабочиебудни</a> <a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-119">

      <div class="body details">
26 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message239">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.01.2024 20:13:03 +07">
20:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет и с пятницей господа и дамы! Отсматривал сегодня очередные домашние Bash задания своих студентов ну и собрал для вас самые распространенные велосипеды, которые в 99% повторяются.<br><br>Оно конечно работает правильно. Но бывалый глаз сразу ощутит жопный дискомфорт глядя на такие конструкции.<br><em><br>Кстати я всегда придерживаюсь правила — одну задачу можно решить разными способами. Работает, да и пёс с ним. Но учить такому других, увы непозволительно, пусть лучше сразу правильно делают. Нормально делай, нормально будет.</em><br><br><strong>Поехали!<br></strong><br><pre>cat bashdays.txt | cut -f 2 -d &apos;;&apos;</pre><br><br>В текстовом файле bashdays.txt у меня забита строка: hello;world. Далее команда <strong>cat</strong> читает этот файл и перенаправляет данные на утилиту <strong>cut</strong> с помощью <strong>pipe «|»</strong>. А <strong>cut</strong> уже режет строку по символу <strong>«;»</strong> и отдает мне второй элемент. То есть на выходе я получу: <strong>«world»</strong>.<br><br>Но. Утилита <strong>cut</strong> сама умеет читать файлы. Проще говоря так:<br><br><pre>cut -f 2 -d &apos;;&apos; bashdays.txt</pre><br><br>Сюда можно приплести и grep, с которым обычно делают так:<br><br><pre>cat bashdays.txt | grep &quot;world&quot;</pre><br><br>Это прям любимый паттерн всех, забит в днк, даже я этим порой грешу. Это как на велосипеде, один раз научился, больше не разучишься. А по хорошему надо делать так:<br><br><pre>grep &quot;world&quot; bashdays.txt</pre><br><br>Ну и к примеру еще такое встречается часто:<br><br><pre>cat bashdays.txt | tr &apos;a-z&apos; &apos;A-Z&apos;</pre><br><br>Суть одна, <strong>cat</strong> передает данные в <strong>tr</strong>, а дальше они конвертятся в верхний регистр и выводятся на экран. По хорошему это было бы так:<br><br><pre>tr &apos;a-z&apos; &apos;A-Z&apos; &lt; bashdays.txt</pre><br><br><em>Но опять же для кого по-хорошему? Мне привычнее вариант с cat, хз, переучиваться я уж точно не буду.</em><br><br>А еще из любимого, это циклы, ща покажу:<br><br><pre>for s in $(ls)  <br>do  <br>    echo &quot;$s&quot;  <br>done</pre><br><br>Это цикл, который перебирает файлы. Тут вообще зачем-то используется вызов внешней утилиты <strong>ls</strong>, хотя она тут вообще не упёрлась. Да и если такое использовать в скриптах, вылезут баги.<br><br>Например, создай такой файл:<br><br><pre>touch &quot;*&quot;</pre><br><br>И заново запусти этот цикл. ООйой… заметил прикол? Вывод продублировал все имена файлов. Вот тебе и баг, а потом сиди полдня, думай, что же оно не работает.<br><br>Этот костыль можно и перекостылисть, указав утилите <strong>ls</strong> параметр <strong>-Q</strong>. Тогда утилита <strong>ls</strong> тепло обнимет кавычками все имена файлов. Но это лишние кавычки, потом их чо? Снова обрезать?<br><br>Правильнее было бы так:<br><br><pre>for s in ./*; do echo &quot;$s&quot;; done</pre><br><br>Не вызывается никакая внешняя утилита, да и безопаснее в разы, в плане наличия багов если у файла будет какое-то корявое имя.<br><br>Перлов конечно много встречается, но это прям основные. Если что-то еще экстренно вспомню, закину в комментарии. Ну либо ты закидывай, мы всегда рады твоей активности!<br><br>Обещал на выходные тебя не беспокоить, но видимо не получится. Так, что увидимся совсем скоро. Хороших тебе предстоящих выходных и береги себя!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;кодревью&quot;)">#кодревью</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-120">

      <div class="body details">
28 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message241">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="28.01.2024 16:24:07 +07">
16:24
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_30@28-01-2024_16-24-07.jpg">

         <img class="photo" src="photos/photo_30@28-01-2024_16-24-07_thumb.jpg" style="width: 260px; height: 132px"/>

        </a>

       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix joined" id="message242">

      <div class="body">

       <div class="pull_right date details" title="28.01.2024 16:24:09 +07">
16:24
       </div>

       <div class="text">
В гугол картинках было найдено такое изображение 👆 на которой запечатлена занимательная закономерность. Если сложить все эти числа, то получится обычное число 42. Ну число и число…<br><br><pre>echo $((7 + 14 + 21))</pre><br><br>Ну дак вот, со времен появления проекта GNU (GNU&apos;s Not Unix) это число имело для них какой-то потаённый смысл. <br><br>К примеру, если в редакторе vi/vim ввести:<br><br><pre>:help 42</pre><br><br>То на мы увидим нечто странное:<br><br><blockquote>Вelection, the selection will be used unmodified.  When there is a selection<br>but you click outside of it, the selection is removed.<br><br>There is a separate popup menu for each mode.  Thus there are never grey<br>items like in the normal menus.<br><br>What is the meaning of life, the universe and everything?  42<br>Douglas Adams, the only person who knew what this question really was about is<br>now dead, unfortunately.  So now you might wonder what the meaning of death<br>is...<br><br>Next chapter: usr_43.txt  Using filetypes<br>Copyright: see manual-copyright  vim:tw=78:ts=8:noet:ft=help:norl:</blockquote><br><br>Но это всего лишь цитата из книги английского писателя Дугласа Адамса «Автостопом по галактике». Где супер компьютер Deep Thought дал ответ на главный вопрос жизни, вселенной и всего остального. И этот ответ был 42.<br><br>В документации к редактору emacs также встречается это число, вот пару примеров:<br><br><blockquote>This situation is best understood in the context of converting text properties during `write-region`. For example, the character at position 42 in a buffer is ‘X’ with a text property `foo`. If the conversion for `foo` is done by inserting into the buffer, say, ‘FOO:’, then that changes the character at position 42 from ‘X’ to ‘F’. The next conversion will start with the wrong data straight away.</blockquote><br><br><blockquote>`ssh` can also take extra parameters as port numbers. For example, a host on port 42 is specified as host#42 (the real host name, a hash sign, then a port number). It is the same as passing ‘-p 42’ to the `ssh` command.</blockquote><br><br>Кроличья нора? Не думаю, книга «Автостопом по галактике» вышла в 1979 году, а ГНУтые появились в 1983 году.<br><br>Все логично, число 42 стало символом для сообщества фанатов научной фантастики и часто упоминается в шутках и широко используется в поп-культуре.<br><br>Существует теория заговора, называемая «42-ой теорией заговора», которая исходит из идеи, что число 42 имеет глубокий смысл или тайное значение, скрытое правительствами или другими могущественными организациями.<br><br>Хотя такие теории заговора могут быть увлекательными, важно отметить, что число 42 не обладает никаким таинственным или сверхъестественным значением в реальном мире. Оно просто является элементом фольклора, шуток и культурных отсылок, и не имеет каких-либо серьезных конспирологических подоплек.<br><br>Так что, так… дело закрыто...<br><br>А ты читал/смотрел «Автостопом по галактике»?<br><br><em><br>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-121">

      <div class="body details">
29 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message244">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="29.01.2024 19:26:26 +07">
19:26
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Всем добрый. Сегодня замусолим про zero bytes. Скорее всего тут единицы про это знают и слышали, значит самое время. Будет интересно и познавательно, рекомендую почитать.<br><br>Термин Zero bytes / Magic zero bytes / Нулевые байты в Linux обычно относят к специальному значению байт 0x00, которое может использоваться для различных целей в контексте файловой системы и прочего.<br><br>Так, стоп, ничо не понятно и даже не интересно. Давай сразу на котиках, погнали в нашу лабораторию. Запускаем:<br><br><pre>read &lt; /dev/zero</pre><br><br>Этой командой я читаю нулевые байты с помощью <strong>read</strong>. По дефолту <strong>read</strong> читает стандартный ввод. Передаем на стандартный ввод магические нули из устройства <strong>/dev/zero</strong> и генерим нулевые байты. Прекратить это безобразие можно комбинацией: <strong>CTRL+C</strong><br><br><em>Вообще /dev/zero это фиктивный файл, который используется для создания файлов, заполненных нулями. А зачем он нужен? Ну например, чтобы отформатировать диск и забить его нулями, чтобы потом никто не смог восстановить данные которые ты удалил. Ну и для экспериментов всяких.</em><br><br>Так, теперь по нашей команде. Запустили, ничего не происходит. Но на самом деле происходит следующее: Оболочка с помощью системного вызова <strong>read</strong> читает в свой буфер нулевые байты из <strong>/dev/zero.</strong> Затем буфер обрабатывается по одному символу, а затем символы помещаются в массив.<br><br>Содержимое этого массива будет присвоено переменной заданной при запуске <strong>read</strong>. По умолчанию эта переменная называется <strong>REPLY</strong>. То есть если в <strong>read</strong> не передать название переменной, то все что ты введешь в нее, очутится в переменной <strong>REPLY</strong>.<br><br><pre>read<br>echo &quot;Ты ввел: $REPLY&quot;</pre><br><br>Вернемся к нашей бесконечной команде, которую запустили в начале поста. Команда так и будет выполняться, так как хочет встретить разделитель строк NL-ASCII или New Line ASCII. Новая строка или «\n».<br><br>А новой строки, то нет. Одни нулевые байты, а эти байты пропускаются. Ну и так, как оболочка не может найти конец строки, получается бесконечный цикл.<br><br>Есть такая штука, называется C-string<br><br><em>C-string - последовательность символов в языке Cи, завершающаяся нулевым символом `\0`. В языке Cи строки представлены массивами символов, где последний символ должен быть нулевым символом, чтобы указать конец строки.</em><br><br>Ну дак вот, для Си нулевой байт это конец строки. Например, функция печати строки выведет символы с начала массива до нулевого байта. Нулевой байт является неким стопером. Если вставить нулевой байт в середину строки, то все что после нулевого байта никогда не выведется на экран.<br><br><strong>Ща покажу как это работает</strong><br><br><pre>cd /tmp<br>cp $(which true) .</pre><br><br>Копируем утилиту true в папку <a href="" onclick="return ShowBotCommand(&quot;tmp&quot;)">/tmp</a>, будем ее патчить нулевыми байтами.<br><br>Смотрим что она нам выводит:<br><br><pre>./true --version</pre><br><br>Выводит дофига всего, меня интересует строка Jim Meyering. Теперь нужно узнать смещение этой строки в бинарном файле.<br><br><pre>strings -dtx -n3 true | grep &apos;Jim Meyering&apos;</pre><br><br><blockquote>Команда strings используется для извлечения читаемых строк из бинарных файлов.</blockquote><br><br><strong>d =</strong> не дублируем повторяющиеся строки<br><strong>t = </strong>разделитель по умолчанию<br><strong>x =</strong> выводим смещение строки <br><strong>n = </strong>минимальная длина строки<br><br>Так, я получил смещение 4176<br><br><pre>4176 Jim Meyering</pre><br><br>Теперь патчим бинарник true:<br><br><pre>dd if=/dev/zero of=./true seek=$((0x4176+3)) conv=notrunc count=1 bs=1</pre><br><br>Тут я заменяю символ пробела на нулевой байт. <strong>Seek</strong> в данном контексте количество блоков, которое нужно пропустить перед началом записи. Берем смещение 4176 и добавляем к нему еще 3 (Jim), после него начинаем запись.<br><br>Команда <strong>dd</strong> скопирует один байт из <strong>/dev/zero</strong> и запишет его в файл по смещению <strong>4176+3</strong>, не обрезая файл.<br><br>Теперь снова запускаем:<br><br><pre>./true --version</pre><br><br>И видим, что часть строки обрезалась нулевым байтом, на экран вывелось:<br><br><pre>Written by Jim.</pre><br><br>А в оригинале выводилось:<br><br><pre>Written by Jim Meyering.</pre><br><br>Вот такие вот магические нули и байты. Я хз зачем тебе это, но момент с патчингом и работой с strings можешь взять на вооружение, штука интересная, возможно где-нибудь применишь.<br><br>Всем еще раз привет, если есть мысли, пишите в комментарии. Пост получился упоротый, но может быть ты его давно ждал. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-122">

      <div class="body details">
31 January 2024
      </div>

     </div>

     <div class="message default clearfix" id="message246">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="31.01.2024 18:22:04 +07">
18:22
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вечерок вчера весёлый получился, в плане отвала RU зоны. Ну да ладно, само все починилось, меня даже ночью не дернули, удалось поспать 5 часов.<br><br>Сегодня продолжим <a href="https://t.me/bashdays/244">тему</a> с нулями, но на этот раз обсудим такое понятие как — Разрежённый файл. Или как их звать-величать «Дырявые файлы».<br><br>Ты всяко в курсе, когда в виртуалке создаешь жесткий диск размером 500 гигабайт, то физический размер этого диска на хостовой машине будет около 1-2х гигабайта, само собой с установленной Linux системой.<br><br><em>Ты суслика видишь? Нет. И я не вижу, а он есть.</em><br><br>А где же все остальное место? А нигде, есть только информация, которая хранится об этом размере в метаданных файловой системы. И по мере необходимости это физическое место на диске выделяется и используется. Сам же файл представляет собой последовательность тех самых нулевых байт (magic zero).<br><br><blockquote>Короче сохраняется только местоположение и количество последовательности нулевых байт. А при чтении такого файла, файловая система генерирует нужное количество нулевых байт.</blockquote><br><br><strong>Если уж совсем просто: </strong>Дырявые файлы - это файлы, которые выделяют пространство на диске только для хранения реально используемых данных.<br><br>Чтобы стало понятнее, давай тыкать палкой.<br><br>Создаем дырявый файл:<br><br><pre>dd if=/dev/zero of=./bashdays bs=1 count=0 seek=100M</pre><br><br>Создался файл bashdays размером 4 мегабайта. Да, не 100, а именно 4ре. Открываем в режиме просмотра и видим в нём нули. По факту его можно растянуть как гандон до 100 мегабайт. Размер будет увеличиваться, по мере заполнения этого файла данными, но не сможет превысить 100 мегабайт.<br><br>Как альтернатива, ты можешь создать такой файл так:<br><br><pre>truncate -s100M ./bashdays</pre><br><br>Окей, файл есть и что дальше? А дальше этот файл нужно чем-то заполнить.<br><br><strong>Дырявые файлы обычно применяются для:</strong><br><br>- экономии места на диске<br>- виртуализации<br>- резервных копий<br>- баз данных <br>- файловых систем<br><br>Очевидно это связанно с оптимизацией, ну и чтобы твой любимый жесткий диск не насиловать физическими записанными нулями.<br><br>Из всего перечисленного, я использую такие разрежённые файлы как файловую систему для экспериментов. Создаю файл, а затем просто монтирую ее как файловую систему, провожу опыты, издеваюсь, растягиваю, а затем удаляю.<br><br>Чтобы примонтировать такой файл как ФС, делаешь так:<br><br><pre>mkfs.ext4 ./bashdays<br>mount ./bashdays /mnt</pre><br><br>Первая накатит туда ext4, а вторая смонтирует в <a href="" onclick="return ShowBotCommand(&quot;mnt&quot;)">/mnt</a>. А еще в такой дырявый файл можно установить операционную систему и даже загрузится в неё. Короче тут кейсов много всяких, все зависит от твоих задач и предпочтений. Но тема да, прикольная. Всякие virtualbox и т.п. это активно используют.<br><br><strong>Теперь про хостеров</strong><br><br>Хостеры и не только, часто используют данную фичу, чтобы раскатывать тебе VPS за несколько секунд, единицы ставят ОС с нуля и выдают «честные» гигабайты на жестком диске. <br><br>Логично, что хостеры НЕ будут резервировать тебе 100 гигабайт места на диске. Возможно ты ими пользоваться вообще не будешь. Чо оно будет просто так болтаться? А денежку конечно же будут брать именно за 100 гигабайт. По факту ты платишь за дырявый файл, который возможно никогда и не заполнится до конца.<br><br>Например, если в яндекс облаке выключить все виртуалки, денежка все равно будет капать за дисковое пространство. Улавливаешь?<br><br><strong>Как это работает:</strong> есть эталонные образы дырявого файла, разного размера. Ты выбираешь у хостера тариф например 2/2/30, затем берется заранее подготовленный дырявый файл с нужным размером диска и отдается тебе.<br><br>Ты видишь (через df -h) что на винте 30 гигабайт, радуешься, но на самом деле это место еще никак не распределено. Используется только 4-5 гигабайта. По мере заполнения данными, заполняется и твой дырявый файл, который тебе продали за 10$ в месяц. Получается так, что в большинстве случаев у тебя в запасе всегда болтается процентов 20 от объема диска, которые ты не используешь, но исправно оплачиваешь.<br><br>Такая вот замечательная бизнес модель, такие вот замечательные разрежённые файлы.<br><br>Казино всегда в плюсе и ставит на <code>/dev/zero.</code> Делайте ваши ставки, дамы и господа!<br><br><strong>UPD: </strong>Коллеги отметили, что лучше так:<code> fallocate -l 1G --punch-hole sparsefile</code><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message247">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="31.01.2024 20:32:48 +07">
20:32
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <div class="media_poll">

         <div class="question bold">
Важный опрос. А есть тут 1С разработчики?
         </div>

         <div class="details">
Anonymous poll
         </div>

         <div class="answer">
- Да, я как раз он/она
         </div>

         <div class="answer">
- Нее...
         </div>

         <div class="total details&#x09;">
1758 votes
         </div>

        </div>

       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-123">

      <div class="body details">
2 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message249">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.02.2024 19:13:03 +07">
19:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Сегодня рассмотрим ситуацию… короче предыстория:<br><br>Я саппортю ебически большой проект на php, в нем миллион файлов и папок. Есть некий файл с выгрузкой для бухов, который генерится по крону и куда-то складывается.<br><br>Знаем точно, что он складывается как раз в тот ебический проект с миллионом файлов. Но не знаем как называется сам файл и где конкретно он сохраняется.<br><br><strong>Задача:</strong> найти местоположение файла с выгрузкой, узнать как называется этот файл и убедиться что файл вообще пытается создаться после запуска крона.<br><br>Естественно нет документации, нет контактов с разработчиками, нет НИЧЕГО у кого можно что-то узнать. Это обычная практика в айти, вот вам проект, ебитесь сами. В общем приступаем к поискам.<br><br>Лазить по каждой папке я не буду, тем более изучать конфиги и насиловать find. Я стараюсь не делать, то что мне не нравится. А вот накидать bash скрипт, это прям хлебом не корми, дай заговнокодить.<br><br>Ладно, давай к делу. Отбрасываем все стандартные методы и скрам практики, <strong>ставим пакет inotify-tools</strong> и накидываем скрипт.<br><br><pre>inotifywait -r -m -e create /var/www/bashdays | while read line; do<br>    echo &quot;Created: $line&quot;<br>done</pre><br><br><blockquote>inotify-tools - это набор утилит командной строки для мониторинга файловой системы в реальном времени на основе inotify, механизма ядра Linux, который позволяет приложениям реагировать на изменения файлов, каталогов или метаданных в файловой системе.</blockquote><br><br>Да, мысль ты правильно понял, я сделал что-то на подобии снифера, который будет рекурсивно перехватывать события создания файла/папки и выводить нужную мне информацию на экран. Проще говоря, как только в папках с проектом что-то создастся, оно закричит и покажет мне, то что создалось.<br><br>Что круто, мониторинг осуществляется рекурсивно, достаточно указать одну папку, а все подпапки автоматически попадут под колпак.<br><br>Запускаем скрипт. В соседней вкладке запускаем команду, которая генерит этот вонючий файл с выгрузкой и ждем. Совсем скоро на экране я получаю такую запись:<br><br><pre>Created: /var/www/bashdays/core/modx/var/tmp CREATE 1C_b2b_prices.csv</pre><br><br>Опа, задача решена, путь до файла определен, как и его имя. Пишем комментарий к задаче, передвигаем её в Done и трекаем 8 часов потраченного времени.<br><br>Вообще игрушка <strong>inotify-tools </strong>достаточно мощная, можно мониторить не только создание файлов, но и кучу еще всего. При должном подходе, можно свой собственный мониторинг собрать, выгружать в prometheus и соплю в grafana рисовать.<br><br>Про все ее возможности писать не буду, всё прекрасно гуглится, да и man у нее хороший. Я лишь показал, как применил эту штуку на реальной задаче и сэкономил кучу времени. А дальше тебе карты в руки.<br><br>А еще есть клевая штука <strong>incrond</strong>, с помощью неё можно запустить какую-нибудь утилитку, если в каком-то каталоге появился новый файл или произойдет другое событие.<br><br>Например, можно дернуть обработчик этого файла, сделать резервную копию, или тегнуть в телеграм. Вариантов масса.<br><br><blockquote>incrond (inotify cron daemon) - это демон для системы Linux, который обеспечивает возможность запуска задач (команд или скриптов) в ответ на события файловой системы, используя механизм inotify. Он подобен стандартному демону cron, но вместо использования времени он реагирует на изменения файлов и каталогов.</blockquote><br><br>Я однажды видел подобную поделку на каком-то сервере у хостера, где админы сильно упарывались с безопасностью, отслеживали вообще любые изменения в рабочих каталогах и слали алерты на любой чих. С фейками для отнятия почт так боролись. Ну не знаю… по моему совсем уж избыточно.<br><br>Ладно, не болей, хороших тебе предстоящих выходных и береги себя!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a> <a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;debug&quot;)">#debug</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-124">

      <div class="body details">
5 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message251">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.02.2024 17:17:46 +07">
17:17
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет, тут на днях <a href="https://t.me/bashday/33746">в нашем чатике</a> пролетала софтина которая делает этакий ханипот на 22 порту. И все кто ломится по ssh просто вязнут в этом болоте.<br><br>Но сегодня не про это. Сегодня про злоумышленников, которые методом тыка пытаются найти и украсть бэкап. Зачастую бэкапы хранятся в папках проекта, либо вообще в корне пылятся годами.<br><br><strong>Как это бывает:</strong> переезжаешь на другой сервер, перетащил проект в zip архиве, распаковал, а сам zip не удалил. И теперь любой кто узнает имя архива, сможет его скачать, со всеми паролями и явками. Ну либо как в распространенных движках, есть всем известная папка, где могут находиться эти бэкапы.<br><br>Вообще руками имена файлов никто не подбирает, для этого есть специальный софт, который просто брутфорсит по словарю всевозможные локейшены и если получает статус 200, то скачивает всё, что плохо лежит.<br><br><strong>Как с этим бороться? </strong>Ничего не бэкапить в папки проекта, удалять промежуточные файлы если что-то переносил, настраивать политики nginx чтобы 403 отдавал и т.п.<br><br><strong>Но есть способ сделать простой ханипот.</strong> Злоумышленник якобы находит бэкап, получает статус 200 и начинает его скачивать. Естественно это не бэкап, а специально подготовленный файл большого размера. Причем такой файл отдается специально с пониженной скоростью и санкциями.<br><br><em>Повторюсь, маловероятно, что злоумышленник это человек. В основном сбором бигдаты занимается автоматизированный софт. Устанавливается на уже скомпрометированные машины, с которых осуществляется сканирование каталогов на наличие плохо лежащих файлов.</em><br><br><strong>Давай настроем такой ханипот на примере nginx</strong><br><br>Добавляем в nginx конфиги:<br><br><pre>location ~* &quot;^/(new|old|bkup|tmp|temp|upload|ftp|sql|file|www|drupal|joomla|wordpress|x|user|admin|a|b|r|rezerv|arch|arx|111|archive|auth|backup|clients|com|dat|dump|engine|files|home|html|index|master|media|my|mysql|old|site|sql|website|wordpress)\.tar.gz$&quot; {<br>    access_log /var/log/nginx/honeypot.log;<br>    default_type application/zip;<br>    root /var/www/bashdayz/files/backup;<br>    rewrite ^(.*)$ /backup break;<br>    max_ranges 0;<br>    limit_rate 4k;<br>    limit_conn addr 1;<br>}<br><br># а это в секцию http<br>limit_conn_zone $binary_remote_addr zone=addr:10m;</pre><br><br>Указываем список на что будем триггериться. Ограничиваем скорость, ограничиваем число потоков, запрещаем докачку.<br><br>Создаем файл затычку размером 1гиг, этого вполне хватит. Но можешь конечно сделать и больше.<br><br><pre>dd if=/dev/zero of=/var/www/bashdayz/files/backup bs=1G count=1</pre><br><br>Вот и всё. Теперь если кто-то попытается вытянуть у тебя бэкап к примеру mysql.tar.gz, то будет страдать. Идея думаю тебе понятна, вокруг нее можно городить вообще сумасшедшие схемы. Но опять же это всего лишь концепт, из которого можно сделать что-то большое и нужное.<br><br>Я одно время применял этот способ в случае, когда коллеги просят выдать бэкап базы. Обычно я даю прямую ссылку на скачивание. Но бывают ситуации, когда разработчики ведут себя как зажравшиеся ЧСВешные мудаки. И на такой случай у меня для них была специальная ссылка для скачивания бэкапа.<br><br>Ничего особенного, но с сюрпризом, бэкап никогда не скачается. Тащить 10 гигабайт со скоростью dial-up ну такое себе. А когда те начинали орать как свинья из avp, мой ответ был простой - проблема на твоей стороне. У меня видишь все работает и показываю скриншот с нормальной скоростью. <br><br>Но таким быть фу, заподлостроением пусть школьники занимаются. Мы с вами взрослые и ответственные ребята. Правда? )<br><br>Ладно, рад всех видеть. Всем хорошей рабочей недели!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;nginx&quot;)">#nginx</a> <a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-125">

      <div class="body details">
7 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message253">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="07.02.2024 19:13:02 +07">
19:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_31@07-02-2024_19-13-02.jpg">

         <img class="photo" src="photos/photo_31@07-02-2024_19-13-02_thumb.jpg" style="width: 210px; height: 260px"/>

        </a>

       </div>

       <div class="text">
Привет. Разгребал тут мамонтовский сервер и нашел исходник с таким артом.<br><br>Думаешь это всего лишь картинка из архивов старого фидошника? Нифига, это Acme EyeDrops. Visual Programming in Perl.<br><br>В арте зашит вполне рабочий perl код. Если сохранить эту картинку в файл и затем выполнить его через интерпретатор, ты получишь секретное сообщение.<br><br><pre>perl ./pokazisiski.pl</pre><br><br>Сам код этого арта, сгенерирован с помощью модуля <a href="https://metacpan.org/pod/Acme::EyeDrops">Acme::EyeDrops.</a> Кстати на странице модуля много примеров с такими картинками (верблюды, морды, заборы, снежинки), каждая выполняет какое-то своё действие + есть примеры генераторов.<br><br>А вот эта команда, превратит файл обратно в исходник. То есть выведет исходный код вместо того, чтобы его выполнить.<br><br><pre>perl -MO=Deparse ./pokazisiski.pl</pre><br><br>Опять же не знаю, что ты будешь делать с этой информацией. Говорят что perl давно мёртв, но в современных скриптах и решениях люди любят его применять. ХЗ почему, наверное потому что perl есть везде. Хотя сейчас глянул, последний релиз был 2024-01-20, версия 5.39.7 (devel), капец, оно живое.<br><br>Первое и последнее, что я делал на perl, это был вывод «Hello World», на этом моё знакомство с ним закончилось. Даже на СИ порог вхождения мне легче показался, хотя по СИ у меня была книга, а по perl только какие-то огрызки из фидонета.<br><br>Ладно. Побежали дальше мир спасать от криворучек. Увидимся!<br><br><strong>А ты применяешь perl в современном мире?</strong> Если да, поделись пожалуйста в комментариях, как и где. Очень интересно.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-126">

      <div class="body details">
8 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message254">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="08.02.2024 15:11:05 +07">
15:11
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Немного терминальной развлекухи :<br><br><pre>curl ascii.live/parrot  <br>curl ascii.live/forrest  <br>curl ascii.live/can-you-hear-me<br>curl parrot.live</pre><br><br>А <a href="https://github.com/hugomd/parrot.live">тут</a> и <a href="https://github.com/hugomd/ascii-live">тут</a> можешь посмотреть исходники этих проектов. Там еще много подобных curl запросов можно понаделать с котиками, пончиками, бэтменами. А еще можно поставить себе на сервер и устраивать консольные вечеринки.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-127">

      <div class="body details">
9 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message256">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="09.02.2024 16:12:43 +07">
16:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Вот и до наших краёв донеслась снежная стихия, какая-то «Ольга». Ну хоть не «Арбузова». С названием переменных явно не заморачивались. Ну да ладно, сегодня тоже будет про переменные в Bash.<br><br>Не все понимают чем отличается определение переменной в Bash c export и без. Сейчас расскажу, чтобы ты больше не сомневался.<br><br>Есть 2 распространенных способа объявить переменную:<br><br><pre>export var=значение<br>var=значение</pre><br><br>Что тут не так? А тут всё так. Только в первом случае я использую export, чтобы сделать переменную доступной для подпроцессов.<br><br>То есть, переменная заданная через export будет доступна для любого процесса, который будет запущен в рамках процесса оболочки. <br><br>А если задать переменную БЕЗ export, то переменная будет доступна только в самой оболочке и недоступна для других процессов.<br><br><strong>Скучная теория, давай на практике:</strong><br><br><pre>var1=&quot;Hello Bashdays&quot;<br>echo $var1<br><br>Hello Bashdays</pre><br><br>Запускаем, смотрим, ага переменная задается без экспорта и выводится на экран. Идем дальше и запускаем это:<br><br><pre>export var1<br>var2=&quot;Bye, Bye&quot;<br>bash<br>echo $var1<br><br>Hello Bashdays<br><br>echo $var2</pre><br><br>1. Экспортируем var1<br>3. Объявляем вторую переменную var2<br>4. Запускаем bash в bash (подпроцесс)<br>5. Получаем значение переменной var1<br>6. Получаем значение переменной var2<br><br>В пятом пункте переменная var1 вывелась на экран даже после того, как я запустил еще одну оболочку bash внутри оболочки bash. Переменная стала доступна для подпроцессов. <br><br>А вот var2 которую я объявил во втором пункте, куда-то делась. На самом деле она никуда не делась, просто подпроцесс её не видит. Стоит мне сейчас сделать так:<br><br><pre>exit<br>echo $var2<br><br>Bye, Bye</pre><br><br>Я получаю значение переменной var2. Если уж совсем грубо говоря, export делает переменную глобальной на уровне подпроцессов.<br><br>Ну и частые ошибки, когда пытаешься экспортировать массив:<br><br><pre>export Array=(&quot;Hello&quot; &quot;Bashdays&quot;)</pre><br><br>С виду все в порядке и вроде логично, ошибок нет. НО в подпроцессах если попытаться вывести содержимое этого массива, ты получишь пустоту. И люди на это убивают несколько часов, чтобы понять в чем причина.<br><br><blockquote>А причина простая, просто нужно знать — в Bash не существует прямой поддержки экспортирования массивов.</blockquote><br><br>Но где наша не пропадала, если уж совсем хочется, то можно преобразовать массив в строку и затем экспортировать эту строку. Делается это так:<br><br><pre>Array=(&quot;Hello&quot; &quot;BashDays&quot;)<br>export ArrayString=&quot;$(printf &quot;%s|&quot; &quot;${Array[@]}&quot;)&quot;<br>IFS=&apos;|&apos; read -ra Array &lt;&lt;&lt; &quot;$ArrayString&quot;<br>echo &quot;${Array[@]}&quot;</pre><br><br>Значок собаки = все элементы массива, его можно справедливо заменить на 1, 2, 3 и т.п. А printf используются для форматирования массива в строку, разделяя элементы символом «|».<br><br>Теперь массив экспортирован и будет доступен в подпроцессах.<br><br>Вообще холиваров на тему экспортирования переменных очень много, каждый топит за своё, но тут уже хозяин барин. Как говорится под каждую задачу своё решение, где-то необходим export, где-то он и не нужен.<br><br>Ладно чо, хороших тебе предстоящих выходных и береги себя!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em> </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-128">

      <div class="body details">
12 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message257">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="12.02.2024 15:12:20 +07">
15:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Странный факт - всю неделю с нетерпением ждешь выходных, а когда дождался, щелчок пальцами и снова наступил понедельник. А когда отдыхать-то? В рабочие дни разгребаешь рабочую рутину, в выходные разгребаешь домашнюю рутину.<br><br>Вот такой вот замкнутый круг получается. С другой стороны ты всегда находишься при деле, в потоке. Меньше времени остается на нытье и на самокопание. А это уже большой плюс. Окей, поныли и хватит, летсгоу!<br><br>Ты тёртый калач и всяко знаешь про специальные переменные со знаком <strong>$</strong>. Держу пари, знаешь только про базовые и часто используемые, типа <strong>$?</strong> и <strong>$1</strong>.<br><br>Сегодня рассмотрим еще парочку <strong>$@</strong> и<strong> $*</strong>. Эти специальные переменные по сути выполняют одну и туже задачу: <strong>выводят список всех аргументов переданных скрипту</strong>. Но естественно есть различия в их использовании.<br><br>Голову не грей, теория всегда душная, сейчас на примерах рассмотрим и всё у тебя в голове сложится как надо.<br><br><strong>Начнем с $@</strong>, накидываем скрипт:<br><br><pre>echo &quot;Изучаем \$@&quot;<br>for arg in $@; do<br>    echo &quot;Аргумент: $arg&quot;<br>done</pre><br><br>Запускаем так: <br><br><pre>./script.sh 1 2 &apos;3 with spaces&apos;</pre><br><br>На экран выводится:<br><br><pre>Изучаем $@<br>Аргумент: 1<br>Аргумент: 2<br>Аргумент: 3<br>Аргумент: with<br>Аргумент: spaces</pre><br><br>Видим что каждый аргумент у нас вывелся отдельным словом. Даже несмотря на то, что последний аргумент у нас заключен в кавычки и является строкой с пробелами. <strong>В этом и особенность.</strong> Он наплевал на кавычки и разбил строку на дополнительные аргументы.<br><br>А теперь немного переделаем скрипт (добавим кавычки) и запустим с теме же аргументами:<br><br><pre>echo &quot;Изучаем \$@ с кавычками&quot;<br>for arg in &quot;$@&quot;; do<br>    echo &quot;Аргумент: $arg&quot;<br>done</pre><br><br>В этот раз на экран выведется такое:<br><br><pre>Изучаем $@ с кавычками<br>Аргумент: 1<br>Аргумент: 2<br>Аргумент: 3 with spaces</pre><br><br>Вот! Тут мы получили уже более ожидаемый результат. Массив: {$1, $2, $3}<br><br><strong>Теперь про $*</strong><br><br><pre>echo &quot;Изучаем \$*&quot;<br>for arg in $*; do<br>    echo &quot;Аргументы: $arg&quot;<br>done</pre><br><br>После запуска с такими же аргументами:<br><br><pre>Изучаем $*<br>Аргументы: 1<br>Аргументы: 2<br>Аргументы: 3<br>Аргументы: with<br>Аргументы: spaces</pre><br><br>Получаем то же самое, что и с <strong>$@</strong> без кавычек. Шило на мыло. А вот если заключить <strong>$*</strong> в кавычки:<br><br><pre>echo &quot;Изучаем \$*&quot;<br>for arg in &quot;$*&quot;; do<br>    echo &quot;Аргументы: $arg&quot;<br>done</pre><br><br>На экране мы получим:<br><br><pre>Изучаем $*<br>Аргументы: 1 2 3 with spaces</pre><br><br>Вот и отличие. Оно небольшое, оно практически ненужное. Но в этом и кроются детали. Все аргументы объединились в одну строку, отделенным символом пробела, заданным в IFS (пробел по умолчанию).<br><br>Если это не знать, то легко можно наступить на грабли.<br><br>Вот пример как заменить IFS разделитель (пробел на запятую):<br><br><pre>echo &quot;Изучаем \$*&quot;<br>IFS=&quot;,&quot;<br>for arg in &quot;$*&quot;; do<br>    echo &quot;Аргументы: $arg&quot;<br>done</pre><br><br>Вывод будет таким:<br><br><pre>Изучаем $*<br>Аргументы: 1,2,3 with spaces</pre><br><br>Как «эффект бабочки», забыл поставить кавычки, сломал в будущем логику. Поставил кавычки, сломал другую логику. Куда не ткни, вечно какие-то костыли.<br><br>Я конечно сомневаюсь, что ты пользуешься таким высокоуровневым программированием (я не пользуюсь), но порой бывает натыкаешься на чужие скрипты с подобной логикой. И тогда важно не попасть в просак.<br><br>А что такое просак, хорошо объясняется в фильме «Жмурки».<br><br>Ладно, не смею тебя больше отвлекать. Увидимся. Хорошего понедельника!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em> </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-129">

      <div class="body details">
14 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message264">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="14.02.2024 17:13:02 +07">
17:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. В прошлом <a href="https://t.me/bashdays/257">посте</a> про мы с тобой познакомились с <strong>$@</strong> и <strong>$*</strong>. Сегодня разберем остатки этих прекрасных баксовых штуковин.<br><br><blockquote>$1/$2/$3 - позиционные параметры переданные в скрипт<br>$# - количество переданных аргументов<br>$- - текущие флаги оболочки<br>$$ - идентификатор процесса PID<br>$_ - последний аргумент предыдущей команды<br>$IFS - разделение слов во входящих данных<br>$? - код возврата последней выполненной команды<br>$! - PID последнего запущенного в фоновом режиме процесса<br>$0 - имя исполняемого файла<br></blockquote><strong><br>Теперь на примерах</strong><br><br><strong>Позиционные параметры</strong><br><br><pre>echo &quot;Первый аргумент: $1&quot;<br>echo &quot;Второй аргумент: $2&quot;<br>echo &quot;Третий аргумент: $3&quot;<br><br>./script.sh one two three</pre><br><br><strong>Выведет:</strong><br><br><pre>Первый аргумент: one<br>Второй аргумент: two<br>Третий аргумент: three</pre><br><br><strong>Количество переданных аргументов</strong><br><br><pre>echo &quot;Количество аргументов: $#&quot;<br><br>./script.sh one two three</pre><br><br><strong>Выведет:</strong><br><br><pre>Количество аргументов: 3</pre><br><br><strong>Текущие флаги оболочки</strong><br><br><pre>echo &quot;Текущие флаги оболочки: $-&quot;</pre><br><br>Выведет:<br><br><pre>Текущие флаги оболочки: himBHs</pre><br><br>Про эти флаги можешь почитать в <a href="https://t.me/bashdays/215">этом</a> посте.<br><br><strong>Идентификатор процесса PID</strong><br><br><pre>echo &quot;PID текущей оболочки: $$&quot;</pre><br><br><strong>Выведет:</strong><br><br><pre>PID текущей оболочки: 362748</pre><br><br><strong>Последний аргумент предыдущей команды</strong><br><br><pre>echo &quot;Hello BashDays&quot;<br>echo &quot;Welcome Home&quot;<br>echo &quot;Последний аргумент предыдущей команды: $_&quot;</pre><br><br><strong>Выведет:</strong><br><br><pre>Последний аргумент предыдущей команды: Welcome Home</pre><br><br><strong>Разделение слов во входящих данных</strong><br><br><pre>IFS=&quot;,&quot; <br>read -ra words &lt;&lt;&lt; &quot;hello,bashdays,how,are,you&quot;<br>for word in &quot;${words[@]}&quot;; do<br>    echo &quot;Слово: $word&quot;<br>done</pre><br><br>По умолчанию у <a href="" onclick="return ShowCashtag(&quot;IFS&quot;)">$IFS</a> это пробел, но можно заменить на что-то другое. Тут указываем, что разделитель у нас будет «запятая».<br><br><strong>Вывод будет таким:</strong><br><br><pre>Слово: hello<br>Слово: bashdays<br>Слово: how<br>Слово: are<br>Слово: you</pre><br><br><strong>Код возврата последней выполненной команды</strong><br><br><pre>ls non_existent_file.txt<br>echo &quot;Код возврата: $?&quot;</pre><br><br><strong>Выведется:</strong><br><br><pre>ls: cannot access &apos;non_existent_file.txt&apos;: No such file or directory<br>Код возврата: 2</pre><br><br><strong>PID последнего запущенного в фоновом режиме процесса</strong><br><br><pre>sleep 10 &amp;<br>echo &quot;PID последнего запущенного в фоновом режиме: $!&quot;</pre><br><br><strong>Выведет:</strong><br><br><pre>PID последнего запущенного в фоновом режиме: 362786</pre><br><br><strong>Имя исполняемого файла</strong><br><br><pre>echo &quot;Имя этого скрипта: $0&quot;</pre><br><br><strong>Выведет:</strong><br><br><pre>Имя этого скрипта: -bash</pre><br><br>А если выполнить из скрипта, то оно покажет его имя.<br><br>Вроде всё упомянул, если что-то упустил, добавляйте в комментарии.<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-130">

      <div class="body details">
15 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message266">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="15.02.2024 16:13:03 +07">
16:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Во времена динозавров, мне удалось поработать в профильных компаниях, которые занимаются информационной безопасностью и тестированием инфраструктуры клиентов на проникновение. <br><br>Однажды обратился клиент, которому злые лоси вынесли инфраструктуру. И когда мы полезли разбирать инцидент, на серверах отсутствовали логи, их просто не было. Их не удалили, их отключили. Тогда еще никто не парился со всякими ELK, да и может таких решений и не существовало вовсе.<br><br>В общем тут мои глаза и раскрылись, а зачем отключают логи? Правильно, чтобы что-то скрыть. Вектор атаки простой - заимел рута, отключил логи, зачистил то что было и делай свои грязные делишки.<br><br>И мне стало интересно, а как это провернуть? А если появился интерес, надо тыкать палкой.<br><br>Сейчас будем решать эту задачу. Как именно, понятия не имею. Будем экспериментировать.<br><br><strong>Отключаем логирование</strong><br><br>Цель -  папка var/log всегда должна быть пустая и чтобы Linux машина не встала раком. Дополнительно обуздаем journald и history от bash.<br><br>Первое, что я проверил, удалил все и запретил вообще любую запись в var/log через chmod 000, но после перезагрузки сервера, всё вернулось на свои места. Права на папку стали 755. Однако…<br><br>Теперь попробуем установить на папку специальный атрибут:<br><br><pre>sudo chattr +i /var/log</pre><br><br>Перезагружаемся. Хе! Сработало. В папке пустота! На этом можно двигать задачу в done.<br><br><em>После установки этого атрибута, у тебя начнет сыпать ошибками apt, но пакеты оно будет ставить, так что имей это ввиду. Это фиксится добавлением строчки Dir::Log &quot;/путь&quot;; в apt.conf.d.</em><br><br><strong>НО, не все так просто. Если ввести:</strong><br><br><pre>jorunalctl -f</pre><br><br>Мы снова видим логи. Но теперь уже на экране. А раз они на экране, значит они где-то лежат и на диске. Давай искать.<br><br>Зачищаем этот системный журнал:<br><br><pre>sudo journalctl --rotate &amp;&amp; sudo journalctl --vacuum-time=1s</pre><br><br>Ага, на экране видим путь, то что оно зачистило, это <strong>/run/log/journal/. </strong><br><br>Зачистка это хорошо, но логи все равно будут писаться. Надо отключить эту шляпу на глобальном уровне.<br><br>Открываем файл /etc/systemd/journald.conf и добавляем:<br><br><pre>Storage=none</pre><br><br>Перезагружаем службу и удаляем остатки:<br><br><pre>sudo systemctl restart systemd-journald<br>rm -R /run/log/journal/*</pre><br><br>Теперь если ввести:<br><br><pre>jorunalctl -f</pre><br><br><strong>Получим такое сообщение: </strong>No journal files were found. Прекрасно!<br><br>Так, если в системе установлен rsyslog или подобное, то дизейблим и его:<br><br><pre>systemctl stop rsyslog<br>systemctl disable rsyslog</pre><br><br>Основное сделали. Осталось логирование в .bash_history. Зачищаем и накидываем атрибут на запрет записи:<br><br><pre>cat /dev/null &gt; ~/.bash_history<br>sudo chattr +i ~/.bash_history<br>history -c &amp;&amp; history -w``<br></pre><br>Либо добавляем в .bashrc строчку: HISTSIZE=0, с ней будет нативнее и без костылей с атрибутом.<br><br>Делаем финальную перезагрузку. Ну вот и всё, задача выполнена. Система зачищена от логирования. По любому я что-то упустил, поэтому жду с нетерпением твои комментарии. <br><br>Вообще все эти способы очень грубые и топорные. Было бы намного изящнее сделать решение, которое удаляет из логов только то, что нужно удалить. Логирование работает в штатном режиме, но критичные данные в логи не попадают.<br><br>Всех обнимаю, хорошего дня!<br><br><em>Прошу отметить, что предоставленная здесь информация предназначена исключительно для образовательных и информационных целей. Я не призываю и не одобряю незаконные действия, и использование этой информации для незаконных целей запрещено. Читатели должны соблюдать законы своей страны и использовать свои навыки с уважением к этическим нормам и законам.</em><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-131">

      <div class="body details">
16 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message268">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="16.02.2024 16:13:03 +07">
16:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_32@16-02-2024_16-13-03.jpg">

         <img class="photo" src="photos/photo_32@16-02-2024_16-13-03_thumb.jpg" style="width: 260px; height: 86px"/>

        </a>

       </div>

       <div class="text">
Занятный факап приключился у клиента. На скрине думаю понятно, что произошло. Добро пожаловать в Linux!<br><br>Эту задачу мне удалось решить за несколько минут, не имея бэкапов я восстановил ему этот удаленный файл. Как раз способом из <a href="https://t.me/bashdays/103">этого</a> поста.<br><br>Если кратко, я глянул в логи /var/log/cron, взял рандомную таску которая выполнялась ранее и вбил:<br><br><pre>grep -a -C 500 -F &apos;console import:reports&apos; /dev/sda1</pre><br><br>Соответственно <strong>console import:reports</strong> это часть таски, которая когда-то выполнялась. Команда отработала и нашла мне удаленный cron файл. Копипаста и все рады. Но тут опять же повезло, что данные не перезаписались на диске.<br><br>В любом случае можно было бы восстановить по хронологии из файла /var/log/cron, но уже с геморроем. Либо грепнуть CRON в syslog и journald.<br><br>На будущее сделал клиенту алиас:<br><br><pre>alias crontab=&quot;crontab -i&quot;</pre><br><br>Этакая защита от дурака и толстых пальцев. Теперь если перепутать «e» и «r», то оно выругается и запросит подтверждение:<br><br><strong>crontab: really delete root&apos;s crontab? (y/n)</strong><br><br>Ну и на будущее, не забывай делать бэкапы. Хотя сколько не говори, никто не делает, пока петух не клюнет. Хотя сколько меня не клевал, я все равно зачастую забиваю, видимо уверен, что смогу всё восстановить.<br><br><strong>Бэкап крона:</strong><br><br><pre>@daily crontab -l &gt; $HOME/.crontab</pre><br><br><strong>Восстановить:</strong><br><br><pre>crontab &lt; $HOME/.crontab</pre><br><br>А вообще часто советуют использовать systemd timers вместо cron или systemd-cron, мол они гибче и безопаснее. Ну хз хз, каждый привык выбирать свои игрушки.<br><br>Всех с пятницей, хороших предстоящих выходных. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-132">

      <div class="body details">
17 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message270">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="17.02.2024 20:13:01 +07">
20:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет. Сегодня про хитрости с пайпами и кодами завершения. Максимально упрощаю, чтобы стало понятнее.<br><br><strong>Собираем такую команду:</strong><br><br><pre>false | true</pre><br><br>Если после её выполнения сделать: echo $?, то получим статус выхода 0. То есть у нас есть статус завершения именно команды true. НО теперь узнать с каким кодом завершилась первая команда false?<br><br>А вот так, модифицируем команду:<br><br><pre>false|true ; ( exit ${PIPESTATUS[0]} )</pre><br><br>В этом случае будет получен код завершения 1, который справедлив для команды false. Как ты можешь заметить, если в PIPESTATUS изменить [0] на [1], мы снова получим статус завершения 0 (то есть для true).<br><br><blockquote>PIPESTATUS - это специальный массив переменных в оболочке Bash, который содержит статус завершения каждой команды в цепочке команд, выполняемой через конвейер (pipeline). Когда в вашем скрипте используется конструкция конвейера с несколькими командами, PIPESTATUS сохраняет статус завершения каждой из этих команд.</blockquote><br><br>Аналогично можно манипулировать любой частью пайпа и получать нужные тебе статусы.<br><br><pre>command1 | command2 | command3<br>echo &quot;${PIPESTATUS[0]}&quot;<br>echo &quot;${PIPESTATUS[1]}&quot;<br>echo &quot;${PIPESTATUS[2]}&quot;</pre><br><br>Есть еще много велосипедов для реализации желаемого, но этот коробочный самый распространенный и понятный. Изучай! <br><br><strong>Больше про коды завершения, можешь найти в </strong><a href="https://t.me/bashdays/80">этом посте.</a><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-133">

      <div class="body details">
19 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message272">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="19.02.2024 18:13:24 +07">
18:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Тадам! Сегодня научимся определять, отправляется ли стандартный вывод скрипта в терминал либо передается с помощью pipe в другой скрипт/утилиту. Чтобы стало понятнее, нужно читать дальше.<br><br>Есть у меня некий Bash скрипт, пусть будет таким:<br><br><pre>echo &quot;Hello Bashdays Welcome&quot;</pre><br><br>Если его выполнить, то на экран выведется ожидаемый результат. Но что если я хочу добавить логику в этот скрипт, которая будет детектить pipe и отдавать другой ожидаемый результат?<br><br><strong>Давай по порядку, смотри:</strong><br><br><pre>bold=$(tput bold)<br>normal=$(tput sgr0)<br><br>echo &quot;Hello ${bold}BashDays${normal} Welcome&quot;</pre><br><br>Этот скрипт выведет строку <em>Hello Bashdays Welcome</em>, где слово Bashdays будет жирным (bold).<br><br>Дальше я хочу, чтобы при использовании pipe, слово BashDays НЕ выделялось жирным. То есть если запустить скрипт самостоятельно, без использования пайпов, то текст будет жирным. Если скрипт запущен через пайп, то текст остается нормальный.<br><br><blockquote>./script.sh<br>Hello Bashdays Welcome<br><br>./script.sh | cat<br>Hello Bashdays Welcome</blockquote><br><br>Пригодится например, чтобы не передавать утилитам всякие ненужные управляющие символы, а на экран выводить опрятную и ухоженную девочку. Про управляющие символы можешь почитать в <a href="https://t.me/bashdays/235">этом посте</a>. <br><br><strong>Давай мутить</strong><br><br>В <a href="https://t.me/bashdays/172">POSIX оболочках</a> существует флаг <strong>-t</strong>, с помощью которого можно задетектить файловый дескриптор. Если файловый дескриптор<strong> fd = True,</strong> то скрипт запущен самостоятельно в терминале. Дескриптор <strong>fd</strong> может принимать значения:<br><br><pre>0 - стандартный ввод<br>1 - стандартный вывод<br>2 - стандартная ошибка</pre><br><br><strong>Пишем скрипт с логикой:</strong><br><br><pre>bold=$(tput bold)<br>normal=$(tput sgr0)<br><br>if [ -t 1 ] ; then<br>    echo &quot;Hello ${bold}BashDays${normal} Welcome&quot;<br>else.<br>    echo &quot;Hello BashDays Welcome&quot;<br>fi</pre><br><br><strong>Запускаем:</strong><br><br><blockquote>./script.sh<br>Hello BashDays Welcome<br><br>./script | cat<br>Hello BashDays Welcome</blockquote><br><br>Видим сработал детект. Скрипт самостоятельно определил, как он был запущен и вывел на экран, то что требуется.<br><br>Флаг <strong>-t</strong> справедлив не только для Bash, он будет работать во всех POSIX оболочках. <br><br>Вот такие вот интересные кейсы порой приходится решать, благо всё это давно придумано за нас, главное знать про эту срань. Ну теперь и ты про неё знаешь.<br><br>Хорошего дня, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-134">

      <div class="body details">
20 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message274">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="20.02.2024 17:19:34 +07">
17:19
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
А спорим ты не знаешь чем отличается:<br><br><pre>var=$(command)</pre><br><br>от<br><br><pre>var=`command`</pre><br><br>Держу пари многие, используют оба варианта даже не задумываясь. Порой в скриптах я могу одновременно встретить как первую, так и вторую конструкцию. И аргумент всегда один - но оно же работает, чо душнишь? <br><br><blockquote>Кстати если в Bash скрипте видишь, что используются обе конструкции, высока вероятность, что скрипт писался копипастой из разных источников.</blockquote><br><br>Если на чистоту, то эти два примера ничем не отличаются, логика работы будет одинакова. Выполнится какая-либо команда (command) и ее результат запишется в переменную var.<br><br><blockquote>Эти штуки, кривые кавычки, называются backticks = обратные палки/знаки или gravemarks = надгробия.</blockquote><br><br>Второй вариант с надгробиями звучит как-то прикольнее, чем какие-то палки-копалки.<br><br><strong>А в чём, тогда подвох?</strong><br><br>Да всё просто - gravemarks (надгробия) морально устарели и в бест-практиках нынче $(command).<br><br>Ну и конечно же при использовании надгробий будет много геморроя например с вложенными командами и экранированием. <strong>Вот пример:</strong><br><br><pre>list=$(ls -l $(cat bashdays.txt))</pre><br><br>либо<br><br><pre>list=`ls -l \`cat bashdays.txt\``</pre><br><br>Очевидно что первый вариант предпочтительнее, чем второй. Предпочтительнее в плане читаемости и ошибку в синтаксисе ты вряд ли допустишь. Ведь чем сложнее будет команда, тем больше этих надгробий придётся использовать. Возникает проблема вложенности.<br><br>Ну и порой использование gravemarks влияет на результаты:<br><br><pre>A=&quot;A_VAR&quot;<br>echo $(echo &quot;\$A&quot;)<br>echo `echo &quot;\$A&quot;`</pre><br><br>Вроде две одинаковые команды, а выведут разный результат:<br><br><pre>$A<br>A_VAR</pre><br><br>Обратная косая черта внутри надгробий обрабатывается неочевидным образом. Но если пропатчить таким образом вторую команду, то все становится на свои места:<br><br><pre>echo `echo &quot;\\$A&quot;`</pre><br><br>В результате получим вывод на экран: <a href="" onclick="return ShowCashtag(&quot;A&quot;)">$A</a> как и в первом варианте с $().<br><br>Вот такие пироги. Так что если до сих пор используешь gravemarks, посмотри в сторону $(), оно как бы правильнее. Но опять же, со своим уставом куда-то там не ходят. Выбор каждого.<br><br>Ладно. Давай краба, увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-135">

      <div class="body details">
21 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message276">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="21.02.2024 20:12:29 +07">
20:12
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Помнишь я писал <a href="https://t.me/bashdays/62">про shellcheck</a>, который проверяет Bash скрипты на синтаксические и подобные ошибки. Ну так вот, у интерпретатора Bash есть подобный функционал прям из коробки.<br><br>Суть - проверить скрипт на ошибки, до запуска.<br><br>Перед запуском скрипта, добавь <strong>флаг -n</strong> и оно тебе скажет, накосячил ты или нет.<br><br>Конечно коробочный вариант не такой гибкий как shellchek, но зато ничего не нужно устанавливать лишнего. Это как nginx -t перед его ребутом. Зачем ставить что-то внешнее, если это уже предусмотрено в самой программе. Ну только если расширить функционал и получить больше плюшек.<br><br>А если работаешь с гитом, можешь сделать pre-hook и гавно в репу уже не улетит (но если постараешься, то улетит):<br><br><pre>bashErr=$(find src/ -type f -name &apos;*.sh&apos; -exec bash -n {} \;  2&gt;&amp;1 &gt; /dev/null)<br>if [ -n &quot;$bashErr&quot; ]; then <br>    echo &quot;$bashErr&quot;<br>    exit 1<br>fi</pre><br><br>После запуска этого хука проверяются все * .sh скрипты в папке src. Пример скрипта с ошибкой:<br><br><pre>echo &quot;Hello Bashdays<br>exit 0</pre><br><br><s>Хуй</s> Хук выдаст тебе сообщение <code>src/script.sh: 7: Syntax error: Unterminated quoted string</code> и запретит (коммитить, пушить в мастер).<br><br>Нечто подобное было прикручено к puppet очень давно в одной студии, был какой-то внутренний линтер на хуке гита, но хлебнул я знатно с ним. Мне пушить, а он на какие-то фантомные пробелы орет падла. Короче как только встал у руля, избавился и от этого вонючего паппета, от хуков и от команды.<br><br>Ну или как вариант можно включать <strong>set -u</strong>, например если переменную не объявил и попытался где-то её использовать.<br><br><blockquote>set -u включает режим обработки неустановленных переменных (также известный как режим nounset). Когда этот режим включен, обращение к неустановленной переменной приведет к ошибке выполнения скрипта.</blockquote><br><br><pre>set -u<br><br>echo &quot;Переменная VAR: $VAR&quot;</pre><br><br><pre>./script.sh: line 3: VAR: unbound variable</pre><br><br><strong>Или так:</strong><br><br><pre>set -o noexec</pre><br><br>Включает режим noexec (режим «нет выполнения»). Когда этот режим включен, скрипт не будет выполняться, а только проверяться на синтаксические ошибки. В общем много вариантов есть, чтобы проверить не запуская.<br><br>А завтра кстати внеплановая пятница! Ждем ждем…<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-136">

      <div class="body details">
22 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message278">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="22.02.2024 18:14:31 +07">
18:14
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
С наступающим! Давным-давно я избавился от OpenVPN и сейчас активно продолжаю использовать WireGuard. Даже порой связываю продакшен сервера wg тоннелями в разных регионах, где нет возможности это сделать из коробки. Стабильно, быстро, бесплатно.<br><br>Всё было хорошо, пока я не повзрослел и не <s>познал джаззз</s> установил себе Windows. Ну и естественно запихал туда официальный гуёвый клиент от wg. А что могло пойти не так? А всё! <br><br>Клиент в рандомный момент показывал средний палец и работал через хуй копыто.<br><br>Приходилось его выгружать, перезапускать службы, иногда передергивать софтверно сетевую карту, чтобы не ребутить машину. Ну такое себе удовольствие… Мне блять/блядь работать надо, а я тут утехами занимаюсь.<br><br>Так я ебался с полгода, но в этот понедельник меня это окончательно заебало! Пошел искать альтернативы, конкретно гуишного клиента. Потому что сама технология wg меня устраивает, не устраивают эти постоянные глюки.<br><br><em>И да, я много гуглил про эти проблемы, они имеются и фиксятся именно, так как я их и фиксил, перезагрузками, службами и другими костылями.</em><br><br>Короче перебрал я разные клиенты, всё шлак, ну и наткнулся на гитхабе на что-то приличное, простое и даже с фичами.<br><br><strong>Называется эта штука TunnlTo</strong>. Работает в коллаборации с WireSock. По бенчмаркам обгоняет даже официальный WG клиент. На странице проекта там все подробно описано, можешь самостоятельно ознакомиться.<br><br><strong>Чо понравилось:</strong><br><br>1. Не глючит, шустрый, не виснет<br>2. Поддержка импорта тоннелей из официального wg клиента<br>3. При загрузки ОС можно автоматом подключать/не подключать VPN<br>4. Разделение приложений, кто идет через VPN, а кто нет<br>5. Ну и конечно другие фичи, какие хз, мне 4х хватает<br><br>В общем мне пока нравится. Заточено под винду, но у маководов и линукс-гиков и так всё хорошо, мой личный пруф.<br><br><a href = "stickers/sticker (26).webp">💻</a> <a href="https://github.com/TunnlTo/desktop-app">Страница проекта на github</a><br><br><em>Неделька выдалась продуктивная и очень нервная, в плане работы, в плане домашней рутины, в плане партнерских интеграций. Надо уже новых коллег к нам приводить, а я всё фигнёй какой-то занимаюсь. Исправлюсь! На выходные сделаем небольшую паузу, буду готовить контент план, чтобы уж совсем из пальца темы не высасывать. Да и ты отдохнешь.</em><br><br>В качестве серваков под VPN я использую AEZA. Да, можно оплачивать РФ картами, серваки там честные, даже GPT работает через них, бана пула адресов не замечено. Иногда раздают промо серваки по 1-2 евро. Кого заинтересует, держи рефссылку. Ссылка не моя, это Дмитрий, админ <a href="https://t.me/bashday">нашего чата</a> порекомендовал этих ребят. Так что, не обессудь, нихуя не реклама, просто полезняшка 👇<br><br><a href="https://aeza.net/?ref=370785">https://aeza.net/?ref=370785</a><br><br>Ну а тебе и твоим близким желаю хороших предстоящих выходных, берегите себя ребят. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;utils&quot;)">#utils</a><em> </em><a href="" onclick="return ShowHashtag(&quot;windows&quot;)">#windows</a><em> </em><a href="" onclick="return ShowHashtag(&quot;networks&quot;)">#networks</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-137">

      <div class="body details">
26 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message280">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="26.02.2024 15:13:03 +07">
15:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Доброе утро! Все выходные разгребал бухгалтерию, да готовил рекламную кампанию на завтра. Даже баг мимолётом поправил у клиента. После подключения ddos-guard, мониторинг сильно засопливил. Ну тут очевидно, docker контейнеры с экспортерами снимают показатели по домену, а домен-то теперь за ddos-guard, пришлось прокинуть hosts файл и ходить напрямую за метриками. <br><br>Ладно. Сегодня на повестке дня: <strong>Зачем добавлять ./ перед исполняемым файлом или скриптом.</strong><br><br>Когда я только начал изучение linux, я столкнулся с проблемой, что не могу выполнить bash скрипт. Вроде и атрибут +x указан, но после запуска получал <s>идинахуй</s>:<br><br><pre>script.sh: command not found</pre><br><br>Интернета тогда не было, максимум на что я мог рассчитывать это Фидонет. Но он мне не понадобился, методом тыка я самостоятельно смог решить задачу с запуском. Наверное знания MSDOS как-то натолкнули поставить перед скриптом символы<code> ./</code><br><br>Но почему так? Это же не логично! Нет, всё логично. Это сделано для безопасности и от кривых рук. <strong>Например:</strong><br><br>Работаешь ты под рутом, заходишь в домашнюю папку какого-нибудь пользователя, делаешь ls и хуяк, нет у тебя больше сервера. А что произошло?<br><br>А произошло то, что в папке пользователя лежал бинарник под названием ls. Который содержал руткит, он то и выполнился. Хотя ты ожидал что выполнится нативная утилита ls. <br><br>Вот поэтому если запускать какую-то дичь или скрипт БЕЗ <code>./ </code>то оболочка будет искать эту дичь/скрипт в указанных каталогах. Которые определены в PATH. Соответственно если домашний каталог пользователя не определен в PATH, то и возникает ошибка command not found.<br><br>А вот когда указываешь <code>./script.sh</code> ты говоришь оболочке - Эй бля! Игнорируй PATH и запускай мне эту пепяку! Да, вот прям отсюда!<br><br>Аналогично можно запускать указывая полный путь к программе/скрипту:<br><br><pre>cd ~<br>./script.sh<br><br># или<br><br>/home/user/script.sh</pre><br><br>Здесь так же PATH будет игнорироваться. Но вопрос остается: Как это может быть мерой безопасности, если эта мера обходится банальным<code> ./ </code>?<br><br>Нууу… это больше для предотвращения несчастных случаев. Указав явно<code> ./</code> ты говоришь оболочке - запусти конкретно этот файл из текущего каталога, а не тот который может лежать в PATH.<br><br>Как вариант, можешь добавить точку в PATH и тогда можешь запускать скрипты без<code> ./</code> например:<br><br><pre>export PATH=$PATH:.<br>script.sh</pre><br><br>Добавляем текущий каталог в PATH. Теперь <code>script.sh</code> выполнится, без указания этого хитрого <code>./ </code>Но так делать не рекомендуется, наступишь на грабли или даже на граблища!<br><strong><br>Так, теперь про cron.</strong> Если хочешь чтобы твои скрипты гарантировано запускались в cron, всегда указывай полные пути до программ/утилит. Так как cron может смотреть в какой-то свой PATH или вообще через sh запускаться. Встречал/встречаю я такие случаи. Поэтому рекомендуется писать скрипты в таком духе:<br><br><pre>CAT=$(which cat)<br>$CAT script.sh</pre><br><br>Определяем полный путь до утилиты cat, а потом уже используем как переменные. Даже если cat не найдется через PATH, скрипт в кроне будет выполнен, так как указаны полные пути. Заметки про PATH можешь глянуть <a href="https://t.me/bashdays/203">в этом посте.</a><br><br>Вот так. Хорошей тебе рабочей недели. Вечерком после интеграции закину еще чтива. На связи!<br><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-138">

      <div class="body details">
27 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message282">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.02.2024 00:14:28 +07">
00:14
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Сегодня на собесе задал кандидату вопрос, а расскажи чем отличается &amp;&amp; и «;» при склейке консольных команд. В ответ получил — а мне это зачем знать? Если с &amp;&amp; не заработало, то поменяю на «;».<br><br>Да и правда, у меня иногда такой же подход. Мне быстрее в моменте поменять одно на другое, чем в гугол лезть. Понятно дело если это выполняешь на критичной инфраструктуре, то такое уже не проканает. Нужно отдавать полный отчет своим действиям.<br><br>Давай разбираться чем отличается:<br><br><pre>command &amp;&amp; command</pre><br><br>от:<br><br><pre>command ; command</pre><br><br><strong>&amp;&amp;</strong> (AND) это логический оператор, а вот <strong>«;»</strong> обычная последовательность действий.<br><br>В первом примере с &amp;&amp;, вторая команда запустится, только в том случае, если первая завершится успешным кодом возврата. Соответственно если первая накроется пиздой, произойдет короткое замыкание и вторая команда даже не соизволит запуститься.<br><br><blockquote>Про статусы и коды возврата можешь почитать в этом посте.</blockquote><br><br>А вот в случае с <strong>«;»</strong>, вторая команда запустится при любых обстоятельствах, конечно если это не kernel panic и при условии если в оболочке не включен <code>set -e</code> (завершение при любых сбоях). <br><br>Да, есть еще конструкция:<br><br><pre>false || echo &quot;hello bashdays&quot;</pre><br><br>Тут у нас логический оператор OR (или). Вторая команда будет запущена, только если первая сыграет в ящик. В примере выше выполнится вторая команда, так как первая всегда завершается с ошибкой. Если false заменить на true, соответственно на экране будет пусто.<br><br>Иногда применяю это в скриптах, когда одна утилита не смогла справиться, подключается вторая.<br><br>База. Тут хочешь не хочешь, оно должно на подкорке быть. Интересно конечно, как людей на вайтишных курсах обучают. Человек отучился 6 месяцев, администратор Linux, диплом. А в голове обезьяна тарелками стучит, администрирует. Хотя тут всё от человека зависит, если ему это не интересно, то никакие курсы ситуацию не изменят.<br><br>Ладно, всякое бывает. Не смею больше задерживать. Спокойной ночи. Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message284">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="27.02.2024 20:13:06 +07">
20:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Внимание, сейчас будем упарываться. Давно не упарывались. Камон в нашу ламповую лабораторию. Сразу не сбегай, возможно узнаешь что-то новенькое или окончательно засвистит фляга.<br><br>Для начала давай создадим две подопытные папки:<br><br><pre>mkdir /tmp/{.libs,.bashdays}</pre><br><br>Теперь скопируем в них нативную утилиту cp (copy):<br><br><pre>cp &quot;$(which cp)&quot; /tmp/.libs/lt-test<br>cp &quot;$(which cp)&quot; /tmp/.bashdays/lt-test</pre><br><br>Скопировали, файлы назвали lt-test.<br><br><strong>Далее запускаем:</strong><br><br><pre>/tmp/.libs/lt-test example.txt .</pre><br><br>В параметрах указываем файл, которого нет. <strong>На экран вывелось:</strong><br><br><pre>test: cannot stat &apos;example.txt&apos;: No such file or directory</pre><br><br><strong>А теперь запускаем:</strong><br><br><pre>/tmp/.bashdays/lt-test example.txt .</pre><br><br><strong>На экран получаем:</strong><br><br><pre>/tmp/.bashdays/lt-test: cannot stat &apos;example.txt&apos;: No such file or directory</pre><br><br>Ну и внимательно сравниваем результаты:<br><br><pre>1. test: cannot stat &apos;example.txt&apos;<br>2. /tmp/.bashdays/lt-test: cannot stat &apos;example.txt&apos;</pre><br><br>Хм, всё же идентично, <strong>почему тогда результаты разные?</strong> В первом случае кусок названия запускаемого файла lt-test вообще обрезан.<br><br>В первом случае путь и прёфикс lt был обрезан, <strong>потому что запуск утилиты был выполнен из директории .libs.</strong><br><br>Всё дело в функции <code>set_program_name</code> которую пихают в ГНУтые утилиты и программы. Эта функция модифицирует путь и имя утилиты если запуск был произведен из папки<strong> .libs</strong>, а затем присваивает результат переменным.<br><br>А потом эти переменные используются для вывода при ошибках или при выводе страницы хелпа.<br><br><blockquote>В GNU утилитах, функция set_program_name используется для установки имени программы, которое будет использоваться в выводе сообщений об ошибках, помощи и других местах, где требуется указание имени программы.</blockquote><br><br><strong>Ну и на закуску тест:</strong><br><br><pre>/tmp/.libs/lt-test --help | head  -1<br>/tmp/bashdays/lt-test --help | head  -1</pre><br><br><strong>Результат тот же:</strong><br><br><pre>1. bash: /tmp/.libs/lt-test --help<br>2. bash: /tmp/bashdays/lt-test --help</pre><br><br>Вся эта байда в программах нужна для корректного отображения имени, при использовании ГНУТого инструмента libtool.<br><br>Как это обрабатывается на самом деле, можешь глянуть в нативном исходнике на СИ <a href="https://git.savannah.gnu.org/cgit/gnulib.git/plain/lib/progname.c">здесь</a>, там и про префикс <strong>lt</strong> и про<strong> .libs</strong> всё прекрасно структурировано. А <a href="https://telegra.ph/Pro-libs-i-prefiks-lt-02-27">здесь</a> можешь ознакомиться с развёрнутым комментарием на эту же тему.<br><br>Короче голову не грей, на этой неделе постараюсь подобным тебя больше не развлекать. Спасибо за внимание!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-139">

      <div class="body details">
29 February 2024
      </div>

     </div>

     <div class="message default clearfix" id="message286">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="29.02.2024 20:13:03 +07">
20:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Привет друзья. Частый вопрос: Можно ли в bash скрипте, каким-то образом временно изменить текущий рабочий каталог для выполнения команды, но остаться в каталоге запуска?<br><br>Да всё можно, а если говорят что нельзя, то это пиздёшь. Формулировка вопроса конечно замысловатая. Сходу в голову приходит вариант использовать <strong>cd</strong> (Change Directory), тип такого:<br><br><pre>cd /tmp/test &amp;&amp; ./exec_command</pre><br><br>После запуска команды, переходим в каталог <code>/tmp/test</code> и выполняем <strong>exec_command</strong>. Логично? Логично! А что если после запуска этой команды, я хочу остаться в том же каталоге из которого запускал эту команду.<br><br><blockquote>Про символы &amp;&amp;/;/|| и т.п. можешь почитать в этой статье.</blockquote><br><br><strong>Вот наглядно что происходит:</strong><br><br><pre>1. &gt; pwd<br>2. /root<br>3. &gt; cd /tmp/test &amp;&amp; ./exec_command<br>4. &gt; pwd<br>5. /tmp/test</pre><br><br>В самой последней строке видим, что каталог изменился. А я хочу оставаться в root!<br><br>Что делать? Есть способы, которые я лично использую в своих bash скриптах. Возможно есть какие-то и другие варианты, если знаешь, пиши в комментарии, будет полезно.<br><br><strong>Способ первый:</strong><br><br>Добавим в скрипт <strong>exec_command</strong> такой код:<br><br><pre>ls</pre><br><br>Запускаем то же самое в круглых скобках:<br><br><pre>1. &gt; pwd<br>2. /root<br>3. &gt; (cd /tmp/test &amp;&amp; ./exec_command)<br>4. a.txt  b.txt  c.txt  exec_command<br>5. &gt; pwd<br>6. /root<br>7. &gt; ls<br>8. profit</pre><br><br><strong>Что мы видим: </strong>после выполнения команды в скобках, отработала команда <code>ls</code> из скрипта и вывела на экран содержимое каталога <code>/tmp/test</code>. Как только произошла магия, всё вернулось обратно в каталог root и вывело на экран содержимое каталога root.<br><br><blockquote>pwd я использую для наглядности, чтобы ты понял суть, в своих скриптах от этого мусора можно избавиться.</blockquote><br><br><strong>Способ второй pushd/popd:</strong><br><br><pre>1. &gt; pwd<br>2. /root<br>3. &gt; pushd /tmp/test<br>4. /tmp/test ~<br>5. &gt; ./exec_command<br>6. a.txt  b.txt  c.txt  exec_command<br>7. &gt; popd<br>8. ~<br>9. &gt; pwd<br>10. /root</pre><br><br>Механика аналогична первому способу. Но используются древние, инопланетные технологии <strong>pushd</strong> и <strong>popd</strong>, это коробочные аналоги <strong>cd</strong> из 80x годов. Местоположение предыдущих каталогов сохраняются в стек (массив). А потом уже из этого стека можно вытаскивать необходимое. Погугли если интересно, есть статейки.<br><br><strong>Ну и бонусом третий способ:</strong><br><br><pre>1. &gt; pwd<br>2. /root<br>3. cd /tmp/test &amp;&amp; ./exec_command<br>4. a.txt  b.txt  c.txt  exec_command<br>5. &gt; pwd<br>6. /tmp/test<br>7. &gt; cd -<br>8. /root</pre><br><br>Здесь используем чистый <strong>cd</strong>, но для возврата в предыдущий каталог используем <strong>cd</strong> с параметром <strong>«-»</strong>. <br><br>В 99% случаев никто этим не пользуется, все привыкли в скриптах использовать <strong>cd</strong> туда-сюда с указанием полных/относительных путей. Но если посмотреть в скрипты коммерческих продуктов, в них активно используются методы с <strong>pushd</strong> и <strong>popd</strong>.<br><br>Легаси? Возможно. Тут наверное дело больше в элегантности. У каждого свои бест-практики, нет неправильных решений. Если задача приносит ожидаемый результат, значит ты всё сделал правильно.<br><br>Ладно, изучай, а я пошёл писать следующий пост про обработку сигналов. И нас тут уже 13к, идем дальше!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-140">

      <div class="body details">
1 March 2024
      </div>

     </div>

     <div class="message default clearfix" id="message288">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="01.03.2024 18:13:02 +07">
18:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<em>Время неумолимо. Кажется ещё сегодня пятница, а уже на горизонте маячит понедельник.</em><br><br>Привет. <strong>Сегодня про сигналы и как с ними взаимодействовать через bash скрипты.</strong> Да те самые SIGINT, SIGTERM, SIGKILL.<br><br>Вероятно ты про них слышал. Ладно, скажу больше, ты даже ими пользуешься. Банально нажимая CTRL+C, ты посылаешь сигнал SIGINT. Этот сигнал позволяет скрипту корректно завершить работу. <br><br>Если прервать скрипт по нажатию CTRL+C, то вернется код ошибки 130 (<code>echo $?</code>). <strong>А откуда взялось 130?</strong> <br><br>Потому что если процесс завершается из-за полученного сигнала, он возвращает значение, которое является суммой 128 и кода сигнала. SIGINT = 2, итого получаем 128+2=130.<br><br><blockquote>Цифра 128 выбрана не случайно, сделано это для того, чтобы избежать конфликтов с другими возвращаемыми значениями процесса. Linux использует значения от 0-127 для обозначения различных ошибок и успешного завершения процесса. Поэтому значения от 128 и выше можно использовать для обозначения сигналов, приведших к завершению процесса, не создавая путаницы с кодами завершения процесса.</blockquote><br><br>Для обработки сигналов, в Bash можно использовать обработчики. Спасибо, капитан!<br><br><strong>Пример обработки сигналов:</strong><br><br><pre>#!/bin/bash<br><br># Функция для обработки SIGINT (Ctrl+C)<br>sigint_handler() {<br>    echo &quot;Caught SIGINT (Ctrl+C). Exiting...&quot;<br>    exit 1<br>}<br><br># Функция для обработки SIGTERM<br>sigterm_handler() {<br>    echo &quot;Caught SIGTERM. Exiting...&quot;<br>    exit 1<br>}<br><br># Установка обработчиков сигналов<br>trap sigint_handler SIGINT<br>trap sigterm_handler SIGTERM<br><br># Главный цикл<br>while true; do<br>    echo &quot;Script is running...&quot;<br>    sleep 1<br>done</pre><br><br>Скрипт запустит бесконечный цикл. Если нажать CTRL+C, сработает хендлер <strong>sigint_handler</strong> и скрипт завершится с кодом 1. Видишь, мы поменяли дефолтный код 130 на 1.<br><br>А хендлер <strong>sigterm_handler</strong> сработает в том случае если скрипт убить через <code>kill -TERM PID</code>. Процесс так же завершится с кодом 1.<br><br>Таким образом в хендлерах мы можем построить любую логику, например вывести слово «хуй». А если выпилить <code>exit 1</code>, то по нажатию CTRL+C скрипт вообще никак не отреагирует на завершение и продолжит выполняться дальше. БЕСКОНЕЧНО!<br><br>Прям море возможностей открывается. В малварях частенько такой подход используют, именно с перехватом и подавлением сигналов. Но это не наша тема, просто для информации.<br><br><blockquote>SIGTERM</blockquote><blockquote> = Этот сигнал обычно отправляется операционной системой при попытке завершения процесса. Обработка SIGTERM позволяет скрипту завершить работу безопасно и корректно освободить ресурсы.</blockquote><br><br>Да, есть еще SIGKILL, а вот его обработать не получится. Он нужен для крайних мер. Например, если из скрипта выше убрать <code>exit 1</code>, то бесконечный цикл удастся завершить только через SIGKILL (<code>kill PID</code>). Ну ту тоже логично, всё продумано.<br><br><em>Но я уверен, что и SIGKILL можно перехватить, правда пока лень с этим разбираться, всяко придется в ядро лезть в strace ковыряться и возможно что-то патчить.</em><br><br>Существуют и другие сигналы SIGHUP / SIGUSR1 / SIGPIPE / SIGCHLD и т.п. но сути это не меняет, пост про перехват сигналов.<br><br>Обработка сигналов, это как юнит тесты, они нужны, но никто их не пишет. Но в бест-практиках очень даже рекомендуется использовать такие обработки.<br><br>В принципе на этом можно и закончить, тему разобрали, база есть, дальше уже от своих потребностей двигайся и наращивай функционал. На собесах кстати иногда спрашивают про обработку сигналов и если на этот вопрос ответить, оффер твой.<br><br>Всех с пятницей, хороших предстоящих выходных и береги себя! Увидимся!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-141">

      <div class="body details">
2 March 2024
      </div>

     </div>

     <div class="message default clearfix" id="message289">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="02.03.2024 15:13:02 +07">
15:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_33@02-03-2024_15-13-02.jpg">

         <img class="photo" src="photos/photo_33@02-03-2024_15-13-02_thumb.jpg" style="width: 260px; height: 248px"/>

        </a>

       </div>

       <div class="text">
О чо на почту сегодня прилетело. Вчера в <a href="https://t.me/bashday">чатике</a> видел, ссылка уже пролетала от Константина, но чет значения не придал. А после этого письма придал.<br><br>Идем по <a href="https://terminator.aeza.net/">этой ссылке</a> и тыкаем какой сервак запустить в браузере, с виндой или линуксом. Проходим капчу если необходимо. Если не запускается, значит мешают всякие adguard и т.п. плагины. У меня в яндекс браузере сразу не заработало, а вот в чистом фоксе норм взлетело.<br><br>Короче под капотом Debian 12 или Windows Server 2016 (14393.6709)  Длительность онлайн сессии 15 минут.<br><br>С докой по сервакам, можешь ознакомиться <a href="https://wiki.aeza.net/oblachnye-servery-vps/besplatnyi-testovyi-server">здесь</a>, там с картинками и всеми подробностями.<br><br>Винда немного подтормаживает, возможно из-за мобильного интернета, но вот пингвин прям как родной запускается.<br><br><em>Ради интереса проверил лицензию winrar, на момент закралась мысль - а что если... Но нет, всего лишь пробная версия на 40 дней. Ну да ладно.</em><br><br>Не знаю, буду ли я этим пользоваться, но в избранное добавил, возможно когда-нибудь пригодится, что-нибудь потестировать.<br><br><strong>Выжимка из доки:</strong><br><br>Мы создали ультимативное решение для частых задач в жизни каждого пользователя сети интернет, включая вашу потребность в:<br><br>- дополнительном рабочем столе<br>- виртуальном браузере для открытия любых веб-сайтов вне личного ПК<br>- сервере для тестирования той или иной сомнительной программы<br>- проверке собственного ПО и скриптов в виртуальной среде<br>- тестировании консольных команд<br>- проверки доступности вашего сайта или приложения<br>- тестировании сайтов, приложений, программ в виртуальной среде<br>- запуске социальной сети, мессенджера или сайта в режиме полного инкогнито<br>- способе удалить папку system32 без риска для здоровья<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;services&quot;)">#services</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-142">

      <div class="body details">
4 March 2024
      </div>

     </div>

     <div class="message default clearfix" id="message291">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="04.03.2024 15:08:05 +07">
15:08
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
Зима меня что-то прям знатно так подзаебала, тысяча одёжек, реанимация автомобиля в -40, то дождь за шиворот, то метель в морду лица. Всё же летом как-то попроще мне кажется, хотя и жара сильно изматывает. Нежные мы стали с этой удалёнкой, жёсткая зависимость от зоны комфорта. Ладно…<br><br>Начинать неделю с ебобо-постов очень не хочется, поэтому давай расслабим булки и решим одну интересную, нетривиальную задачку.<br><br>Можно ли после запуска скрипта, перенаправить STDOUT и STDERR в другое место, не останавливая сам скрипт/процесс? Ответ ты и сам знаешь, конечно можно! Ща покажу как.<br><br>Чтобы все стало понятным, берем для эксперимента такую команду и запускаем ее в терминале.<br><br><pre>tail -f /var/log/auth.log &amp;</pre><br><br>Запускаем в фоне просмотр логов авторизации. Задачка запустилась в фоне и отдала нам консоль обратно в интерактивное состояние.<br><br>Как только в файле <strong>auth.log</strong> появляются новые записи, оно начинает нам срать в терминал, мешая дальнейшей работе. Хоть задача и запущена в фоне, но активно работает с текущим <strong>tty</strong> и <strong>stdout</strong>.<br><br>Чтобы нам все это дело отправить в <strong>dev/null</strong> не останавливая фоновую задачу/скрипт. Проделываем следующий трюк:<br><br><pre>ps aux | grep tail</pre><br><br><strong>Узнаём PID процесса</strong>, в моём случае это <strong>1327692</strong>, далее <strong>смотрим файловые дескрипторы</strong> этого процесса:<br><br><pre>ls -l /proc/1327692/fd</pre><br><br><strong>Получаем нечто подобное:</strong><br><br><pre>0 -&gt; /dev/pts/1<br>1 -&gt; /dev/pts/1<br>2 -&gt; /dev/pts/1<br>3 -&gt; /var/log/auth.log</pre><br><br>Знакомо? <strong>stdout = 1</strong> (поток вывода), <strong>stderr = 2</strong> (поток с ошибками) и т.п. Уже наталкивает на мысль чо будем делать? Нет? Поехали дальше.<br><br>Теперь каким-то образом, надо зареврайтить это говнище в <strong>dev/null</strong>. Для этого будем использовать утилиту gdb, она обычно идет в коробке либо ставится через апт-инсталл.<br><br><blockquote>gdb - отладчик для программ, написанных на Си. Отладчик позволяет выполнить программу пошагово, посмотреть значения всех переменных на каждом из этапов выполнения, а если это необходимо, то и дизассемблировать код и посмотреть состояние регистров процессора.</blockquote><br><br><strong>Запускаем кракена:</strong><br><br><pre>gdb -p 1327692 /usr/bin/tail</pre><br><br>Подключаемся к процессу <strong>1327692</strong> и указываем путь до <strong>tail</strong>. На экран вывалит кучу всякого мусора, не пугайся, он тебе не нужен.<br><br>Всё, теперь ты находишься в «хакерской» оболочке (gdb), начинаем реврайтить говнище. Вводим такие команды:<br><br><pre>p (int) dup2((int) open(&quot;/dev/null&quot;, 0), 1)<br>p (int) dup2((int) open(&quot;/dev/null&quot;, 0), 2)</pre><br><br>На экран получишь нечто подобное:<br><br><pre>$1 = 1<br>$2 = 2</pre><br><br>После этого закрываем gdb:<br><br><pre>detach<br>quit</pre><br><br>Вот и всё. Говнище из <strong>auth.log</strong> перестало выводиться на экран, хотя фоновый процесс продолжает работать. Смотрим что у нас получилось:<br><br><pre>ls -l /proc/1327692/fd</pre><br><br>И видим что наш реврайт сработал:<br><br><pre>0 -&gt; /dev/pts/1<br>1 -&gt; /dev/null<br>2 -&gt; /dev/null<br>3 -&gt; /var/log/auth.log<br>4 -&gt; anon_inode:inotify<br>5 -&gt; /dev/null<br>6 -&gt; /dev/null</pre><br><br>Теперь <strong>stdout(1)</strong> и <strong>stderr(2) </strong>смотрят в <strong>dev/null</strong>, собственно этого мы и желали добиться.<br><br><strong>Разберем команды gdb</strong><br><br><strong>«p» (print)</strong>, выводим результат команды на экран.<br><br><strong>«dup2»</strong>, дублирует файловый дескриптор. Первым аргументом идет файловый дескриптор, который нужно продублировать. Второй аргумент это новый файловый дескриптор, который нужно использовать.<br><br>Все это дело приводим к типу Int, хотя раньше и без этого всё отлично работало, видимо что-то поменялось.<br><br><strong>И получается такое: </strong>Команда сначала открывает файл <strong>dev/null</strong>, затем дублирует его файловый дескриптор, а затем перенаправляет <strong>stdout</strong> в этот файл. Прозрачно? Прозрачно!<br><br>Вот такие пироги. Надеюсь было интересно.<br><br><blockquote>Кстати чтобы не упарываться с gdb, существует софтина под названием reredirect, делает то же самое, если интересно, можешь потыкать, ссылка git на репозиторий.</blockquote><br><br><strong>Ставь лайк, подписывайся, рекомендуй друзьям. Хорошей тебе рабочей недели!</strong><br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href = "stickers/AnimatedSticker (4).tgs">💩</a> <a href="https://t.me/+68hWB_gbcaMwYmEy">@bashdays</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-143">

      <div class="body details">
5 March 2024
      </div>

     </div>

     <div class="message default clearfix" id="message292">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.03.2024 15:00:10 +07">
15:00
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_34@05-03-2024_15-00-10.jpg">

         <img class="photo" src="photos/photo_34@05-03-2024_15-00-10_thumb.jpg" style="width: 260px; height: 130px"/>

        </a>

       </div>

       <div class="text">
<a href = "stickers/AnimatedSticker (12).tgs">💻</a> <strong>Готовим новое исследование отечественного рынка DevOps</strong>. Это большой разговор с топ-менеджерами и разработчиками, которые развивают DevSecOps для разработки собственного ПО или внедрения готового продукта.<br><br><a href = "stickers/AnimatedSticker (13).tgs">🔔</a> Примите участие в исследовании, регистрируйтесь по <a href="https://xn----qtbiicagik.xn--p1ai/942861/?erid=2SDnjezzCNU&amp;utm_source=telegram&amp;utm_medium=social&amp;utm_campaign=wp&amp;utm_term=bashdays">ссылке</a> и получите результат первым! <br><br><u>В фокусе исследования: </u><br><br><a href = "stickers/sticker (27).webp">⚫️</a>Текущее состояние рынка ИТ с фокусом на DevSecOps<br><a href = "stickers/sticker (27).webp">⚫️</a>Готовность перехода компаний на облачные технологии, взаимодействие с DevOps инструментами<br><a href = "stickers/sticker (27).webp">⚫️</a>Основные тренды в сфере безопасности DevSecOps<br><a href = "stickers/sticker (27).webp">⚫️</a>Рынок специалистов DevSecOps — где искать сотрудников и как изменились зарплаты<br><a href = "stickers/sticker (27).webp">⚫️</a>Рейтинги DevOps инструментов и оценка степени использования подходов DevOps в организациях<br><br><a href="https://xn----qtbiicagik.xn--p1ai/942861/?erid=2SDnjezzCNU&amp;utm_source=telegram&amp;utm_medium=social&amp;utm_campaign=wp&amp;utm_term=bashdays">Станьте респондентом</a> Russia DevOps Report 2023.<br>Результаты представим уже в апреле!<br><br>Реклама. <a href="https://telegra.ph/OOO-T1-Didzhital-03-04">Информация о рекламодателе</a>
       </div>

       <div class="signature details">
Posted
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message293">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="05.03.2024 17:13:01 +07">
17:13
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<a href = "stickers/AnimatedSticker (14).tgs">🅰️</a><a href = "stickers/AnimatedSticker (14).tgs">🅰️</a><a href = "stickers/AnimatedSticker (14).tgs">🅰️</a><br><strong>7 причин, почему коты делают «тыгыдык»</strong><br><br>Вчера наконец-то собрался силами и добрался до иммобилайзера, всего-то понадобилась неделя. За 5 дней я знатно себе так жопу отморозил без автозапуска. Починил, правда палец сука порезал. Ну это капля в море, на фоне всратых сервисов и неоправданных счетов за ремонт.<br><br>Благо сейчас есть интернет, где можно найти буквально любую инфу по багфиксу хоть чего, главное не ссать. Разобрал, посмотрел умным взглядом, собрал, если пару лишних деталей осталось, то уже успех.<br><br><strong>Ну и вот, к чему это я.</strong> Спустя несколько лет жизни на алиасах, у меня дошли руки забиндить себе в bash хитрую хоткейку.<br><br>Сейчас покажу очередной велосипед, который сэкономит мне еще пару секунд прибывания в консоли. А может быть и ты куда-нибудь себе это присобачишь. Погнали!<br><br>Есть у меня сервер, на нем крутится самописная bastion оболочка. Как это работает:<br><br>1. Цепляюсь в bastion<br>2. В консоль вываливает список серверов<br>3. Коннект к серверу <code>ssh &lt;index&gt;</code><br><br>То есть bastion у меня единая точка входа чтобы попасть на другие сервера, даже если на них нет белых айпишников.<br><br><blockquote>Bastion я написал, впечатлившись этим решением от ITSumma, которое называется isolate.</blockquote><br><br><strong>Как я подключался раньше</strong><br><br><pre>&gt; ssh user@bastion.bashdays.com</pre><br><br><strong>Как я подключался потом</strong><br><br><pre>&gt; export alias bas=&quot;ssh user@bastion.bashdays.com&quot;<br>&gt; bas</pre><br><br><strong>Как я подключаюсь сейчас</strong><br><br><pre>&gt; alt+b</pre><br><br>Прям эволюционный роадмэп. Интересно, какая стадия будет следующей. Итак, повесил я подключение на хоткей, стало довольно удобно. Только открылась консоль, бряк <strong>alt+b</strong> и я уже внутри.<br><br>Хоткей вешал так, добавив это в <strong>.bahsrc:</strong><br><br><pre>bastion() {<br>    echo &quot;connect to bastion server&quot;<br>    ssh -t qa@bastion.bashdays.com &apos;reset;bash&apos;<br>}<br><br>bind -x &apos;&quot;\eb&quot;: bastion&apos;</pre><br><br><strong>«ёб»</strong> в последней строчке, это как раз клавиша <strong>alt+b</strong> в кодах ANSI escape sequences. Если нужны другие кнопки, го в гугол, там этого полно.<br><br><strong>«-t»</strong> создаёт псевдотерминал, чтобы команды вводились на сервере, а не в текущей оболочке.<br><br>А <strong>reset;bash</strong> понадобился, чтобы победить проблему с отображением команд, которые вводишь. Если убрать это хак, то когда будешь что-то вводить в консоли, это не будет отображаться на экране.<br><br>В zsh я на быструю руку попытался подобное провернуть, оно даже подключается, но терминал впадает в бэдтрип Read Only, какая-то абстракция с псевдотерминалами. Пока руки не дошли докопаться до сути. Но если у тебя получится это завести, пиши в комменты, сделаешь ОЧЕНЬ нужное и доброе дело.<br><br><strong>Вот мои наработки для .zshrc:</strong><br><br><pre>bastion() {<br>    echo &quot;connect to bastion server&quot;<br>    ssh -tt user@bastion.bashdays.com<br>}<br><br>zle -N bastion<br>bindkey &apos;\eb&apos; bastion</pre><br><br><em>Так, совсем забыл про котов, эту тему обязательно нужно обсудить. И дело тут не в блуждающем нерве.</em><br><br>На хоткеи ты можешь повесить любую команду, любой комбайн, который только заблагорассудится, например можешь запускать vim или редактирование файла /etc/hosts. Короче изучай.<br><br>И давай краба, жду тебя в комментах!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href="https://t.me/+68hWB_gbcaMwYmEy">@BASHDAYS</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

     <div class="message service" id="message-144">

      <div class="body details">
6 March 2024
      </div>

     </div>

     <div class="message default clearfix" id="message294">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.03.2024 18:00:14 +07">
18:00
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="media_wrap clearfix">

        <a class="photo_wrap clearfix pull_left" href="photos/photo_35@06-03-2024_18-00-14.jpg">

         <img class="photo" src="photos/photo_35@06-03-2024_18-00-14_thumb.jpg" style="width: 260px; height: 260px"/>

        </a>

       </div>

       <div class="text">
<a href = "stickers/sticker (28).webp">🏆</a> Чтобы получить новые знания, опыт совместной работы и общение с лучшими экспертами, пройдите предварительную регистрацию в Летних школах Яндекса 2024!<br><br>Больше 50% выпускников становятся стажёрами и сотрудниками Яндекса<a href = "stickers/sticker (29).webp">💪</a><br><br>В этом году будет запущено больше школ:<br><a href = "stickers/sticker (30).webp">🔸</a> Школа бэкенд-разработки;<br><a href = "stickers/sticker (30).webp">🔸</a> Школа разработки интерфейсов;<br><a href = "stickers/sticker (30).webp">🔸</a> Школа мобильной разработки;<br><a href = "stickers/sticker (30).webp">🔸</a> Школа менеджеров Яндекса;<br><a href = "stickers/sticker (30).webp">🔸</a> Школа аналитиков-разработчиков.<br><br>После лекций в онлайне будет практика в офисах Яндекса в Москве, Санкт-Петербурге и Екатеринбурге. Вам оплатят проезд и проживание, если вы из другого города<a href = "stickers/sticker (31).webp">📍</a><br><br><a href="https://yandex.ru/yaintern/schools/summer?utm_source=telegram&amp;utm_medium=social&amp;utm_campaign=sschool24&amp;utm_content=bashdays&amp;utm_term=promoshool&amp;erid=5C7FMwRgLbGCLypSvRZ2X4dPP4NVUyR3EWbTx1fK7HYgJUr5rQ16C2VDpwHomsBh">👉Подать заявку</a>
       </div>

       <div class="signature details">
Posted
       </div>

      </div>

     </div>

     <div class="message default clearfix" id="message295">

      <div class="pull_left userpic_wrap">

       <div class="userpic userpic8" style="width: 42px; height: 42px">

        <div class="initials" style="line-height: 42px">
B
        </div>

       </div>

      </div>

      <div class="body">

       <div class="pull_right date details" title="06.03.2024 20:07:23 +07">
20:07
       </div>

       <div class="from_name">
Bash Days | Linux | DevOps 
       </div>

       <div class="text">
<strong>Что случится, если отключить буферизацию</strong><br><br>Привет. Чтобы результаты вывода софта/скриптов отображались без задержек в реальном времени — отключи буферизацию.<br><br>На практике, эффект буферизации незаметен, либо софт/скрипты и так работают в реальном времени. <br><br><strong>Распространенный случай.</strong><br><br>Ты всяко с таким сталкивался: запустил программу, которая пишет данные в файл. И пока софтина не отработает, файл с результатами, визуально пустой. Грыжа!<br><br>Но хочется же в реальном времени наблюдать, как файл заполняется и делать выводы. А что если софтина работает 10 часов? А выхлоп нужен вчера?<br><br><pre>/usr/local/sbin/script.sh &amp;&gt; bashdays.log</pre><br><br>Проблема этого условного скрипта, в том, что файл <strong>bashdays.log</strong> создаётся только, после выполнения скрипта. Как отслеживать прогресс?<br><br><strong>Воспользуйся отключением буферизации!</strong><br><br>Всё делается с помощью утилиты <strong>stdbuf</strong>. Утилита изменяет способ буферизации программ.<br><br><pre>stdbuf -oL /usr/local/sbin/script.sh &amp;&gt; bashdays.log</pre><br><br>Ключ <strong>«o»</strong> взаимодействует со стандартным выводом (stdout). А аргумент <strong>«L»</strong> означает Line buffered, то есть, буферизация по строкам.<br><br><blockquote>По умолчанию при перенаправлении в файл, стандартный вывод (stdout) полностью буферизуется и записывается в файл после сброса.</blockquote><br><br>В примере выше, буфер очищается после каждой строки вывода. А в файле <strong>bashdays.log</strong> появится долгожданный результат, без мучительного ожидания.<br><br><strong>Одно из применений stdbuf:</strong><br><br><pre>stdbuf -oL nohup /usr/local/sbin/script.sh &amp;&gt; bashdays.log</pre><br><br>Если закрыть вкладку с сессией, скрипт продолжит работу.<br><br>Либо можешь воспользоваться утилитой<strong> script</strong>:<br><br><pre>script -c &lt;PROGRAM&gt; -f bashdays.txt</pre><br><br>Ключ <strong>«f»</strong> выполняет аналогичную функцию, после каждой операции, запускается flush, запись на диск.<br><br>На этом смею откланяться, хорошего дня/вечера!<br><br><em>tags: </em><a href="" onclick="return ShowHashtag(&quot;bash&quot;)">#bash</a> <a href="" onclick="return ShowHashtag(&quot;linux&quot;)">#linux</a><em><br></em>—<br><a href="https://t.me/+68hWB_gbcaMwYmEy">@BASHDAYS</a>
       </div>

       <div class="signature details">
Роман Шубин
       </div>

      </div>

     </div>

    </div>

   </div>

  </div>

 </body>

</html>
